OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Toolbox to manage all the json files in this directory. | 6 """Toolbox to manage all the json files in this directory. |
7 | 7 |
8 It can reformat them in their canonical format or ensures they are well | 8 It can reformat them in their canonical format or ensures they are well |
9 formatted. | 9 formatted. |
10 """ | 10 """ |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 class Error(Exception): | 86 class Error(Exception): |
87 """Processing error.""" | 87 """Processing error.""" |
88 | 88 |
89 | 89 |
90 def get_isolates(): | 90 def get_isolates(): |
91 """Returns the list of all isolate files.""" | 91 """Returns the list of all isolate files.""" |
92 files = subprocess.check_output(['git', 'ls-files'], cwd=SRC_DIR).splitlines() | 92 files = subprocess.check_output(['git', 'ls-files'], cwd=SRC_DIR).splitlines() |
93 return [os.path.basename(f) for f in files if f.endswith('.isolate')] | 93 return [os.path.basename(f) for f in files if f.endswith('.isolate')] |
94 | 94 |
95 | 95 |
96 def process_builder_convert(data, filename, builder, test_name): | 96 def process_builder_convert(data, test_name): |
97 """Converts 'test_name' to run on Swarming in 'data'. | 97 """Converts 'test_name' to run on Swarming in 'data'. |
98 | 98 |
99 Returns True if 'test_name' was found. | 99 Returns True if 'test_name' was found. |
100 """ | 100 """ |
101 result = False | 101 result = False |
102 for test in data['gtest_tests']: | 102 for test in data['gtest_tests']: |
103 if test['test'] != test_name: | 103 if test['test'] != test_name: |
104 continue | 104 continue |
105 test.setdefault('swarming', {}) | 105 test.setdefault('swarming', {}) |
106 if not test['swarming'].get('can_use_on_swarming_builders'): | 106 if not test['swarming'].get('can_use_on_swarming_builders'): |
107 print('- %s: %s' % (filename, builder)) | |
108 test['swarming']['can_use_on_swarming_builders'] = True | 107 test['swarming']['can_use_on_swarming_builders'] = True |
109 result = True | 108 result = True |
110 return result | 109 return result |
111 | 110 |
112 | 111 |
113 def process_builder_remaining(data, filename, builder, tests_location): | 112 def process_builder_remaining(data, filename, builder, tests_location): |
114 """Calculates tests_location when mode is --remaining.""" | 113 """Calculates tests_location when mode is --remaining.""" |
115 for test in data['gtest_tests']: | 114 for test in data['gtest_tests']: |
116 name = test['test'] | 115 name = test['test'] |
117 if test.get('swarming', {}).get('can_use_on_swarming_builders'): | 116 if test.get('swarming', {}).get('can_use_on_swarming_builders'): |
118 tests_location[name]['count_run_on_swarming'] += 1 | 117 tests_location[name]['count_run_on_swarming'] += 1 |
119 else: | 118 else: |
120 tests_location[name]['count_run_local'] += 1 | 119 tests_location[name]['count_run_local'] += 1 |
121 tests_location[name]['local_configs'].setdefault( | 120 tests_location[name]['local_configs'].setdefault( |
122 filename, []).append(builder) | 121 filename, []).append(builder) |
123 | 122 |
124 | 123 |
125 def process_file(mode, test_name, tests_location, filepath, ninja_targets, | 124 def process_file(mode, test_name, tests_location, filepath, ninja_targets, |
126 ninja_targets_seen): | 125 ninja_targets_seen): |
127 """Processes a file. | 126 """Processes a json file describing what tests should be run for each recipe. |
128 | 127 |
129 The action depends on mode. Updates tests_location. | 128 The action depends on mode. Updates tests_location. |
130 | 129 |
131 Return False if the process exit code should be 1. | 130 Return False if the process exit code should be 1. |
132 """ | 131 """ |
133 filename = os.path.basename(filepath) | 132 filename = os.path.basename(filepath) |
134 with open(filepath) as f: | 133 with open(filepath) as f: |
135 content = f.read() | 134 content = f.read() |
136 try: | 135 try: |
137 config = json.loads(content) | 136 config = json.loads(content) |
(...skipping 18 matching lines...) Expand all Loading... | |
156 for d in data['gtest_tests']: | 155 for d in data['gtest_tests']: |
157 if (d['test'] not in ninja_targets and | 156 if (d['test'] not in ninja_targets and |
158 d['test'] not in SKIP_NINJA_TO_GN_TARGETS): | 157 d['test'] not in SKIP_NINJA_TO_GN_TARGETS): |
159 raise Error('%s: %s / %s is not listed in ninja_to_gn.pyl.' % | 158 raise Error('%s: %s / %s is not listed in ninja_to_gn.pyl.' % |
160 (filename, builder, d['test'])) | 159 (filename, builder, d['test'])) |
161 elif d['test'] in ninja_targets: | 160 elif d['test'] in ninja_targets: |
162 ninja_targets_seen.add(d['test']) | 161 ninja_targets_seen.add(d['test']) |
163 | 162 |
164 config[builder]['gtest_tests'] = sorted( | 163 config[builder]['gtest_tests'] = sorted( |
165 data['gtest_tests'], key=lambda x: x['test']) | 164 data['gtest_tests'], key=lambda x: x['test']) |
166 if mode == 'remaining': | 165 |
166 # The trick here is that process_builder_remaining() is called before | |
167 # process_builder_convert() so tests_location can be used to know how many | |
168 # tests were converted. | |
169 if mode in ('convert', 'remaining'): | |
167 process_builder_remaining(data, filename, builder, tests_location) | 170 process_builder_remaining(data, filename, builder, tests_location) |
168 elif mode == 'convert': | 171 if mode == 'convert': |
169 process_builder_convert(data, filename, builder, test_name) | 172 process_builder_convert(data, test_name) |
170 | 173 |
171 expected = json.dumps( | 174 expected = json.dumps( |
172 config, sort_keys=True, indent=2, separators=(',', ': ')) + '\n' | 175 config, sort_keys=True, indent=2, separators=(',', ': ')) + '\n' |
173 if content != expected: | 176 if content != expected: |
174 if mode in ('convert', 'write'): | 177 if mode in ('convert', 'write'): |
175 with open(filepath, 'wb') as f: | 178 with open(filepath, 'wb') as f: |
176 f.write(expected) | 179 f.write(expected) |
177 if mode == 'write': | 180 if mode == 'write': |
178 print('Updated %s' % filename) | 181 print('Updated %s' % filename) |
179 else: | 182 else: |
180 print('%s is not in canonical format' % filename) | 183 print('%s is not in canonical format' % filename) |
181 print('run `testing/buildbot/manage.py -w` to fix') | 184 print('run `testing/buildbot/manage.py -w` to fix') |
182 return mode != 'check' | 185 return mode != 'check' |
183 return True | 186 return True |
184 | 187 |
185 | 188 |
186 def print_remaining(test_name,tests_location): | 189 def print_convert(test_name, tests_location): |
190 """Prints statistics for a test being converted for use in a CL description. | |
191 """ | |
192 data = tests_location[test_name] | |
193 print('Convert %s to run exclusively on Swarming' % test_name) | |
194 print('') | |
195 print( | |
196 '%d configs used to already run on Swarming' % | |
Dirk Pranke
2015/06/23 19:25:41
"%d configs already ran on Swarming" maybe?
M-A Ruel
2015/06/23 19:29:51
Done.
| |
197 data['count_run_on_swarming']) | |
Dirk Pranke
2015/06/23 19:24:39
this formatting is a bit odd; why isn't the string
| |
198 print('%d used to run locally and were converted:' % data['count_run_local']) | |
199 for master, builders in sorted(data['local_configs'].iteritems()): | |
200 for builder in builders: | |
201 print('- %s: %s' % (master, builder)) | |
202 print('') | |
203 print('Ran:') | |
204 print(' ./manage.py --convert %s' % test_name) | |
205 print('') | |
206 print('R=') | |
207 print('BUG=98637') | |
208 | |
209 | |
210 def print_remaining(test_name, tests_location): | |
187 """Prints a visual summary of what tests are yet to be converted to run on | 211 """Prints a visual summary of what tests are yet to be converted to run on |
188 Swarming. | 212 Swarming. |
189 """ | 213 """ |
190 if test_name: | 214 if test_name: |
191 if test_name not in tests_location: | 215 if test_name not in tests_location: |
192 raise Error('Unknown test %s' % test_name) | 216 raise Error('Unknown test %s' % test_name) |
193 for config, builders in sorted( | 217 for config, builders in sorted( |
194 tests_location[test_name]['local_configs'].iteritems()): | 218 tests_location[test_name]['local_configs'].iteritems()): |
195 print('%s:' % config) | 219 print('%s:' % config) |
196 for builder in sorted(builders): | 220 for builder in sorted(builders): |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 | 300 |
277 extra_targets = set(ninja_targets) - ninja_targets_seen | 301 extra_targets = set(ninja_targets) - ninja_targets_seen |
278 if extra_targets: | 302 if extra_targets: |
279 if len(extra_targets) > 1: | 303 if len(extra_targets) > 1: |
280 extra_targets_str = ', '.join(extra_targets) + ' are' | 304 extra_targets_str = ', '.join(extra_targets) + ' are' |
281 else: | 305 else: |
282 extra_targets_str = list(extra_targets)[0] + ' is' | 306 extra_targets_str = list(extra_targets)[0] + ' is' |
283 raise Error('%s listed in ninja_to_gn.pyl but not in any .json files' % | 307 raise Error('%s listed in ninja_to_gn.pyl but not in any .json files' % |
284 extra_targets_str) | 308 extra_targets_str) |
285 | 309 |
286 if args.mode == 'remaining': | 310 if args.mode == 'convert': |
311 print_convert(args.test_name, tests_location) | |
312 elif args.mode == 'remaining': | |
287 print_remaining(args.test_name, tests_location) | 313 print_remaining(args.test_name, tests_location) |
288 return result | 314 return result |
289 except Error as e: | 315 except Error as e: |
290 sys.stderr.write('%s\n' % e) | 316 sys.stderr.write('%s\n' % e) |
291 return 1 | 317 return 1 |
292 | 318 |
293 | 319 |
294 if __name__ == "__main__": | 320 if __name__ == "__main__": |
295 sys.exit(main()) | 321 sys.exit(main()) |
OLD | NEW |