| 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 |