OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Meta checkout manager supporting both Subversion and GIT. | 6 """Meta checkout manager supporting both Subversion and GIT. |
7 | 7 |
8 Files | 8 Files |
9 .gclient : Current client configuration, written by 'config' command. | 9 .gclient : Current client configuration, written by 'config' command. |
10 Format is a Python script defining 'solutions', a list whose | 10 Format is a Python script defining 'solutions', a list whose |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
597 for s in self.dependencies: | 597 for s in self.dependencies: |
598 work_queue.enqueue(s) | 598 work_queue.enqueue(s) |
599 | 599 |
600 @gclient_utils.lockedmethod | 600 @gclient_utils.lockedmethod |
601 def _run_is_done(self, file_list, parsed_url): | 601 def _run_is_done(self, file_list, parsed_url): |
602 # Both these are kept for hooks that are run as a separate tree traversal. | 602 # Both these are kept for hooks that are run as a separate tree traversal. |
603 self._file_list = file_list | 603 self._file_list = file_list |
604 self._parsed_url = parsed_url | 604 self._parsed_url = parsed_url |
605 self._processed = True | 605 self._processed = True |
606 | 606 |
607 def RunHooksRecursively(self, options): | 607 @staticmethod |
608 """Evaluates all hooks, running actions as needed. run() | 608 def GetHookAction(hook_dict, matching_file_list): |
609 must have been called before to load the DEPS.""" | 609 """Turns a parsed 'hook' dict into an executable command.""" |
610 assert self.hooks_ran == False | 610 logging.debug(hook_dict) |
| 611 logging.debug(matching_file_list) |
| 612 command = hook_dict['action'][:] |
| 613 if command[0] == 'python': |
| 614 # If the hook specified "python" as the first item, the action is a |
| 615 # Python script. Run it by starting a new copy of the same |
| 616 # interpreter. |
| 617 command[0] = sys.executable |
| 618 if '$matching_files' in command: |
| 619 splice_index = command.index('$matching_files') |
| 620 command[splice_index:splice_index + 1] = matching_file_list |
| 621 return command |
| 622 |
| 623 def GetHooks(self, options): |
| 624 """Evaluates all hooks, and return them in a flat list. |
| 625 |
| 626 RunOnDeps() must have been called before to load the DEPS. |
| 627 """ |
| 628 result = [] |
611 if not self.should_process or not self.recursion_limit: | 629 if not self.should_process or not self.recursion_limit: |
612 # Don't run the hook when it is above recursion_limit. | 630 # Don't run the hook when it is above recursion_limit. |
613 return | 631 return result |
614 # If "--force" was specified, run all hooks regardless of what files have | 632 # If "--force" was specified, run all hooks regardless of what files have |
615 # changed. | 633 # changed. |
616 if self.deps_hooks: | 634 if self.deps_hooks: |
617 # TODO(maruel): If the user is using git or git-svn, then we don't know | 635 # TODO(maruel): If the user is using git or git-svn, then we don't know |
618 # what files have changed so we always run all hooks. It'd be nice to fix | 636 # what files have changed so we always run all hooks. It'd be nice to fix |
619 # that. | 637 # that. |
620 if (options.force or | 638 if (options.force or |
621 isinstance(self.parsed_url, self.FileImpl) or | 639 isinstance(self.parsed_url, self.FileImpl) or |
622 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or | 640 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or |
623 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): | 641 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): |
624 for hook_dict in self.deps_hooks: | 642 for hook_dict in self.deps_hooks: |
625 self._RunHookAction(hook_dict, []) | 643 result.append(self.GetHookAction(hook_dict, [])) |
626 else: | 644 else: |
627 # Run hooks on the basis of whether the files from the gclient operation | 645 # Run hooks on the basis of whether the files from the gclient operation |
628 # match each hook's pattern. | 646 # match each hook's pattern. |
629 for hook_dict in self.deps_hooks: | 647 for hook_dict in self.deps_hooks: |
630 pattern = re.compile(hook_dict['pattern']) | 648 pattern = re.compile(hook_dict['pattern']) |
631 matching_file_list = [ | 649 matching_file_list = [ |
632 f for f in self.file_list_and_children if pattern.search(f) | 650 f for f in self.file_list_and_children if pattern.search(f) |
633 ] | 651 ] |
634 if matching_file_list: | 652 if matching_file_list: |
635 self._RunHookAction(hook_dict, matching_file_list) | 653 result.append(self.GetHookAction(hook_dict, matching_file_list)) |
636 for s in self.dependencies: | 654 for s in self.dependencies: |
637 s.RunHooksRecursively(options) | 655 result.extend(s.GetHooks(options)) |
| 656 return result |
638 | 657 |
639 def _RunHookAction(self, hook_dict, matching_file_list): | 658 def RunHooksRecursively(self, options): |
640 """Runs the action from a single hook.""" | 659 assert self.hooks_ran == False |
641 # A single DEPS file can specify multiple hooks so this function can be | |
642 # called multiple times on a single Dependency. | |
643 #assert self.hooks_ran == False | |
644 self._hooks_ran = True | 660 self._hooks_ran = True |
645 logging.debug(hook_dict) | 661 for hook in self.GetHooks(options): |
646 logging.debug(matching_file_list) | 662 try: |
647 command = hook_dict['action'][:] | 663 gclient_utils.CheckCallAndFilterAndHeader( |
648 if command[0] == 'python': | 664 hook, cwd=self.root.root_dir, always=True) |
649 # If the hook specified "python" as the first item, the action is a | 665 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
650 # Python script. Run it by starting a new copy of the same | 666 # Use a discrete exit status code of 2 to indicate that a hook action |
651 # interpreter. | 667 # failed. Users of this script may wish to treat hook action failures |
652 command[0] = sys.executable | 668 # differently from VC failures. |
653 | 669 print >> sys.stderr, 'Error: %s' % str(e) |
654 if '$matching_files' in command: | 670 sys.exit(2) |
655 splice_index = command.index('$matching_files') | |
656 command[splice_index:splice_index + 1] = matching_file_list | |
657 | |
658 try: | |
659 gclient_utils.CheckCallAndFilterAndHeader( | |
660 command, cwd=self.root.root_dir, always=True) | |
661 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | |
662 # Use a discrete exit status code of 2 to indicate that a hook action | |
663 # failed. Users of this script may wish to treat hook action failures | |
664 # differently from VC failures. | |
665 print >> sys.stderr, 'Error: %s' % str(e) | |
666 sys.exit(2) | |
667 | 671 |
668 def subtree(self, include_all): | 672 def subtree(self, include_all): |
669 """Breadth first recursion excluding root node.""" | 673 """Breadth first recursion excluding root node.""" |
670 dependencies = self.dependencies | 674 dependencies = self.dependencies |
671 for d in dependencies: | 675 for d in dependencies: |
672 if d.should_process or include_all: | 676 if d.should_process or include_all: |
673 yield d | 677 yield d |
674 for d in dependencies: | 678 for d in dependencies: |
675 for i in d.subtree(include_all): | 679 for i in d.subtree(include_all): |
676 yield i | 680 yield i |
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1447 'version of all repositories to reproduce the tree, ' | 1451 'version of all repositories to reproduce the tree, ' |
1448 'implies -a') | 1452 'implies -a') |
1449 (options, args) = parser.parse_args(args) | 1453 (options, args) = parser.parse_args(args) |
1450 client = GClient.LoadCurrentConfig(options) | 1454 client = GClient.LoadCurrentConfig(options) |
1451 if not client: | 1455 if not client: |
1452 raise gclient_utils.Error('client not configured; see \'gclient config\'') | 1456 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
1453 client.PrintRevInfo() | 1457 client.PrintRevInfo() |
1454 return 0 | 1458 return 0 |
1455 | 1459 |
1456 | 1460 |
| 1461 def CMDhookinfo(parser, args): |
| 1462 """Output the hooks that would be run by `gclient runhooks`""" |
| 1463 (options, args) = parser.parse_args(args) |
| 1464 options.force = True |
| 1465 client = GClient.LoadCurrentConfig(options) |
| 1466 if not client: |
| 1467 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| 1468 client.RunOnDeps(None, []) |
| 1469 print '; '.join(' '.join(hook) for hook in client.GetHooks(options)) |
| 1470 return 0 |
| 1471 |
| 1472 |
1457 def Command(name): | 1473 def Command(name): |
1458 return getattr(sys.modules[__name__], 'CMD' + name, None) | 1474 return getattr(sys.modules[__name__], 'CMD' + name, None) |
1459 | 1475 |
1460 | 1476 |
1461 def CMDhelp(parser, args): | 1477 def CMDhelp(parser, args): |
1462 """Prints list of commands or help for a specific command.""" | 1478 """Prints list of commands or help for a specific command.""" |
1463 (_, args) = parser.parse_args(args) | 1479 (_, args) = parser.parse_args(args) |
1464 if len(args) == 1: | 1480 if len(args) == 1: |
1465 return Main(args + ['--help']) | 1481 return Main(args + ['--help']) |
1466 parser.print_help() | 1482 parser.print_help() |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1565 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1581 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
1566 print >> sys.stderr, 'Error: %s' % str(e) | 1582 print >> sys.stderr, 'Error: %s' % str(e) |
1567 return 1 | 1583 return 1 |
1568 | 1584 |
1569 | 1585 |
1570 if '__main__' == __name__: | 1586 if '__main__' == __name__: |
1571 fix_encoding.fix_encoding() | 1587 fix_encoding.fix_encoding() |
1572 sys.exit(Main(sys.argv[1:])) | 1588 sys.exit(Main(sys.argv[1:])) |
1573 | 1589 |
1574 # vim: ts=2:sw=2:tw=80:et: | 1590 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |