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 """MB - the Meta-Build wrapper around GYP and GN | 6 """MB - the Meta-Build wrapper around GYP and GN |
7 | 7 |
8 MB is a wrapper script for GYP and GN that can be used to generate build files | 8 MB is a wrapper script for GYP and GN that can be used to generate build files |
9 for sets of canned configurations and analyze them. | 9 for sets of canned configurations and analyze them. |
10 """ | 10 """ |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 cmd = self.GNCmd('gen', path, vals['gn_args']) | 329 cmd = self.GNCmd('gen', path, vals['gn_args']) |
330 | 330 |
331 swarming_targets = [] | 331 swarming_targets = [] |
332 if self.args.swarming_targets_file: | 332 if self.args.swarming_targets_file: |
333 # We need GN to generate the list of runtime dependencies for | 333 # We need GN to generate the list of runtime dependencies for |
334 # the compile targets listed (one per line) in the file so | 334 # the compile targets listed (one per line) in the file so |
335 # we can run them via swarming. We use ninja_to_gn.pyl to convert | 335 # we can run them via swarming. We use ninja_to_gn.pyl to convert |
336 # the compile targets to the matching GN labels. | 336 # the compile targets to the matching GN labels. |
337 contents = self.ReadFile(self.args.swarming_targets_file) | 337 contents = self.ReadFile(self.args.swarming_targets_file) |
338 swarming_targets = contents.splitlines() | 338 swarming_targets = contents.splitlines() |
339 ninja_targets_to_labels = ast.literal_eval(self.ReadFile(os.path.join( | 339 gn_isolate_map = ast.literal_eval(self.ReadFile(os.path.join( |
340 self.chromium_src_dir, 'testing', 'buildbot', 'ninja_to_gn.pyl'))) | 340 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) |
341 gn_labels = [] | 341 gn_labels = [] |
342 for target in swarming_targets: | 342 for target in swarming_targets: |
343 if not target in ninja_targets_to_labels: | 343 if not target in gn_isolate_map: |
344 raise MBErr('test target "%s" not found in %s' % | 344 raise MBErr('test target "%s" not found in %s' % |
345 (target, '//testing/buildbot/ninja_to_gn.pyl')) | 345 (target, '//testing/buildbot/gn_isolate_map.pyl')) |
346 gn_labels.append(ninja_targets_to_labels[target]) | 346 gn_labels.append(gn_isolate_map[target]['label']) |
347 | 347 |
348 gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps') | 348 gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps') |
349 | 349 |
350 # Since GN hasn't run yet, the build directory may not even exist. | 350 # Since GN hasn't run yet, the build directory may not even exist. |
351 self.MaybeMakeDirectory(self.ToAbsPath(path)) | 351 self.MaybeMakeDirectory(self.ToAbsPath(path)) |
352 | 352 |
353 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') | 353 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') |
354 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) | 354 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) |
355 | 355 |
356 ret, _, _ = self.Run(cmd) | 356 ret, _, _ = self.Run(cmd) |
357 | 357 |
358 for target in swarming_targets: | 358 for target in swarming_targets: |
359 if sys.platform == 'win32': | 359 if sys.platform == 'win32': |
360 deps_path = self.ToAbsPath(path, target + '.exe.runtime_deps') | 360 deps_path = self.ToAbsPath(path, target + '.exe.runtime_deps') |
361 else: | 361 else: |
362 deps_path = self.ToAbsPath(path, target + '.runtime_deps') | 362 deps_path = self.ToAbsPath(path, target + '.runtime_deps') |
363 if not self.Exists(deps_path): | 363 if not self.Exists(deps_path): |
364 raise MBErr('did not generate %s' % deps_path) | 364 raise MBErr('did not generate %s' % deps_path) |
365 | 365 |
366 command, extra_files = self.GetIsolateCommand(target, vals) | 366 command, extra_files = self.GetIsolateCommand(target, vals, |
| 367 gn_isolate_map) |
367 | 368 |
368 runtime_deps = self.ReadFile(deps_path).splitlines() | 369 runtime_deps = self.ReadFile(deps_path).splitlines() |
369 | 370 |
370 isolate_path = self.ToAbsPath(path, target + '.isolate') | 371 isolate_path = self.ToAbsPath(path, target + '.isolate') |
371 self.WriteFile(isolate_path, | 372 self.WriteFile(isolate_path, |
372 pprint.pformat({ | 373 pprint.pformat({ |
373 'variables': { | 374 'variables': { |
374 'command': command, | 375 'command': command, |
375 'files': sorted(runtime_deps + extra_files), | 376 'files': sorted(runtime_deps + extra_files), |
376 } | 377 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 ret, _, _ = self.Run(cmd) | 442 ret, _, _ = self.Run(cmd) |
442 if not ret and self.args.verbose: | 443 if not ret and self.args.verbose: |
443 outp = json.loads(self.ReadFile(self.args.output_path[0])) | 444 outp = json.loads(self.ReadFile(self.args.output_path[0])) |
444 self.Print() | 445 self.Print() |
445 self.Print('analyze output:') | 446 self.Print('analyze output:') |
446 self.PrintJSON(outp) | 447 self.PrintJSON(outp) |
447 self.Print() | 448 self.Print() |
448 | 449 |
449 return ret | 450 return ret |
450 | 451 |
451 def GetIsolateCommand(self, target, vals): | 452 def RunGNIsolate(self, vals): |
452 extra_files = [] | 453 build_path = self.args.path[0] |
| 454 inp = self.ReadInputJSON(['targets']) |
| 455 if self.args.verbose: |
| 456 self.Print() |
| 457 self.Print('isolate input:') |
| 458 self.PrintJSON(inp) |
| 459 self.Print() |
| 460 output_path = self.args.output_path[0] |
453 | 461 |
454 # TODO(dpranke): We should probably pull this from | 462 for target in inp['targets']: |
455 # the test list info in //testing/buildbot/*.json, | 463 runtime_deps_path = self.ToAbsPath(build_path, target + '.runtime_deps') |
456 # and assert that the test has can_use_on_swarming_builders: True, | |
457 # but we hardcode it here for now. | |
458 test_type = {}.get(target, 'gtest_test') | |
459 | 464 |
| 465 if not self.Exists(runtime_deps_path): |
| 466 self.WriteFailureAndRaise('"%s" does not exist' % runtime_deps_path, |
| 467 output_path) |
| 468 |
| 469 command, extra_files = self.GetIsolateCommand(target, vals, None) |
| 470 |
| 471 runtime_deps = self.ReadFile(runtime_deps_path).splitlines() |
| 472 |
| 473 |
| 474 isolate_path = self.ToAbsPath(build_path, target + '.isolate') |
| 475 self.WriteFile(isolate_path, |
| 476 pprint.pformat({ |
| 477 'variables': { |
| 478 'command': command, |
| 479 'files': sorted(runtime_deps + extra_files), |
| 480 'read_only': 1, |
| 481 } |
| 482 }) + '\n') |
| 483 |
| 484 self.WriteJSON( |
| 485 { |
| 486 'args': [ |
| 487 '--isolated', |
| 488 self.ToSrcRelPath('%s/%s.isolated' % (build_path, target)), |
| 489 '--isolate', |
| 490 self.ToSrcRelPath('%s/%s.isolate' % (build_path, target)), |
| 491 ], |
| 492 'dir': self.chromium_src_dir, |
| 493 'version': 1, |
| 494 }, |
| 495 isolate_path + 'd.gen.json', |
| 496 ) |
| 497 |
| 498 return 0 |
| 499 |
| 500 def GetIsolateCommand(self, target, vals, gn_isolate_map): |
460 # This needs to mirror the settings in //build/config/ui.gni: | 501 # This needs to mirror the settings in //build/config/ui.gni: |
461 # use_x11 = is_linux && !use_ozone. | 502 # use_x11 = is_linux && !use_ozone. |
462 # TODO(dpranke): Figure out how to keep this in sync better. | 503 # TODO(dpranke): Figure out how to keep this in sync better. |
463 use_x11 = (sys.platform == 'linux2' and | 504 use_x11 = (sys.platform == 'linux2' and |
464 not 'target_os="android"' in vals['gn_args'] and | 505 not 'target_os="android"' in vals['gn_args'] and |
465 not 'use_ozone=true' in vals['gn_args']) | 506 not 'use_ozone=true' in vals['gn_args']) |
466 | 507 |
467 asan = 'is_asan=true' in vals['gn_args'] | 508 asan = 'is_asan=true' in vals['gn_args'] |
468 msan = 'is_msan=true' in vals['gn_args'] | 509 msan = 'is_msan=true' in vals['gn_args'] |
469 tsan = 'is_tsan=true' in vals['gn_args'] | 510 tsan = 'is_tsan=true' in vals['gn_args'] |
470 | 511 |
471 executable_suffix = '.exe' if sys.platform == 'win32' else '' | 512 executable_suffix = '.exe' if sys.platform == 'win32' else '' |
472 | 513 |
473 if test_type == 'gtest_test': | 514 test_type = gn_isolate_map[target]['type'] |
474 extra_files.append('../../testing/test_env.py') | 515 cmdline = [] |
| 516 extra_files = [] |
475 | 517 |
476 if use_x11: | 518 if use_x11 and test_type == 'windowed_test_launcher': |
477 # TODO(dpranke): Figure out some way to figure out which | 519 extra_files = [ |
478 # test steps really need xvfb. | 520 'xdisplaycheck', |
479 extra_files.append('xdisplaycheck') | 521 '../../testing/test_env.py', |
480 extra_files.append('../../testing/xvfb.py') | |
481 | |
482 cmdline = [ | |
483 '../../testing/xvfb.py', | 522 '../../testing/xvfb.py', |
484 '.', | 523 ] |
485 './' + str(target), | 524 cmdline = [ |
486 '--brave-new-test-launcher', | 525 '../../testing/xvfb.py', |
487 '--test-launcher-bot-mode', | 526 '.', |
488 '--asan=%d' % asan, | 527 './' + str(target), |
489 '--msan=%d' % msan, | 528 '--brave-new-test-launcher', |
490 '--tsan=%d' % tsan, | 529 '--test-launcher-bot-mode', |
491 ] | 530 '--asan=%d' % asan, |
492 else: | 531 '--msan=%d' % msan, |
493 cmdline = [ | 532 '--tsan=%d' % tsan, |
| 533 ] |
| 534 elif test_type in ('windowed_test_launcher', 'console_test_launcher'): |
| 535 extra_files = [ |
| 536 '../../testing/test_env.py' |
| 537 ] |
| 538 cmdline = [ |
494 '../../testing/test_env.py', | 539 '../../testing/test_env.py', |
495 '.', | |
496 './' + str(target) + executable_suffix, | 540 './' + str(target) + executable_suffix, |
497 '--brave-new-test-launcher', | 541 '--brave-new-test-launcher', |
498 '--test-launcher-bot-mode', | 542 '--test-launcher-bot-mode', |
499 '--asan=%d' % asan, | 543 '--asan=%d' % asan, |
500 '--msan=%d' % msan, | 544 '--msan=%d' % msan, |
501 '--tsan=%d' % tsan, | 545 '--tsan=%d' % tsan, |
502 ] | 546 ] |
| 547 elif test_type in ('raw'): |
| 548 extra_files = [] |
| 549 cmdline = [ |
| 550 './' + str(target) + executable_suffix, |
| 551 ] + gn_isolate_map[target].get('args') |
| 552 |
503 else: | 553 else: |
504 # TODO(dpranke): Handle script_tests and other types of swarmed tests. | 554 self.WriteFailureAndRaise('No command line for %s found (test type %s).' |
505 self.WriteFailureAndRaise('unknown test type "%s" for %s' % | 555 % (target, test_type), output_path=None) |
506 (test_type, target), output_path=None) | |
507 | |
508 | 556 |
509 return cmdline, extra_files | 557 return cmdline, extra_files |
510 | 558 |
511 def ToAbsPath(self, build_path, *comps): | 559 def ToAbsPath(self, build_path, *comps): |
512 return os.path.join(self.chromium_src_dir, | 560 return os.path.join(self.chromium_src_dir, |
513 self.ToSrcRelPath(build_path), | 561 self.ToSrcRelPath(build_path), |
514 *comps) | 562 *comps) |
515 | 563 |
516 def ToSrcRelPath(self, path): | 564 def ToSrcRelPath(self, path): |
517 """Returns a relative path from the top of the repo.""" | 565 """Returns a relative path from the top of the repo.""" |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 | 785 |
738 if __name__ == '__main__': | 786 if __name__ == '__main__': |
739 try: | 787 try: |
740 sys.exit(main(sys.argv[1:])) | 788 sys.exit(main(sys.argv[1:])) |
741 except MBErr as e: | 789 except MBErr as e: |
742 print(e) | 790 print(e) |
743 sys.exit(1) | 791 sys.exit(1) |
744 except KeyboardInterrupt: | 792 except KeyboardInterrupt: |
745 print("interrupted, exiting", stream=sys.stderr) | 793 print("interrupted, exiting", stream=sys.stderr) |
746 sys.exit(130) | 794 sys.exit(130) |
OLD | NEW |