Chromium Code Reviews| 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 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 578 for s in self.dependencies: | 578 for s in self.dependencies: |
| 579 work_queue.enqueue(s) | 579 work_queue.enqueue(s) |
| 580 | 580 |
| 581 @gclient_utils.lockedmethod | 581 @gclient_utils.lockedmethod |
| 582 def _run_is_done(self, file_list, parsed_url): | 582 def _run_is_done(self, file_list, parsed_url): |
| 583 # Both these are kept for hooks that are run as a separate tree traversal. | 583 # Both these are kept for hooks that are run as a separate tree traversal. |
| 584 self._file_list = file_list | 584 self._file_list = file_list |
| 585 self._parsed_url = parsed_url | 585 self._parsed_url = parsed_url |
| 586 self._processed = True | 586 self._processed = True |
| 587 | 587 |
| 588 def RunHooksRecursively(self, options): | 588 @staticmethod |
| 589 """Evaluates all hooks, running actions as needed. run() | 589 def GetHookAction(hook_dict, matching_file_list): |
| 590 must have been called before to load the DEPS.""" | 590 """Turn a parsed 'hook' dict into an executable command.""" |
| 591 assert self.hooks_ran == False | 591 logging.debug(hook_dict) |
|
M-A Ruel
2012/01/31 01:15:25
FTR, you'll have to remove these before committing
szager
2012/01/31 06:47:39
I don't mind removing them (done), but why? These
M-A Ruel
2012/01/31 15:18:33
I'm stupid. You can add these back.
| |
| 592 logging.debug(matching_file_list) | |
| 593 command = hook_dict['action'][:] | |
| 594 if command[0] == 'python': | |
| 595 # If the hook specified "python" as the first item, the action is a | |
| 596 # Python script. Run it by starting a new copy of the same | |
| 597 # interpreter. | |
| 598 command[0] = sys.executable | |
| 599 if '$matching_files' in command: | |
| 600 splice_index = command.index('$matching_files') | |
| 601 command[splice_index:splice_index + 1] = matching_file_list | |
| 602 return command | |
| 603 | |
| 604 def GetHooks(self, options, result=None): | |
|
M-A Ruel
2012/01/31 01:15:25
I think it'd be simpler if you simply returned the
szager
2012/01/31 06:47:39
Done.
| |
| 605 """Evaluate all hooks, and return them in a flat list. | |
| 606 | |
| 607 run() must have been called before to load the DEPS. | |
| 608 """ | |
| 609 result = [] if result is None else result | |
|
M-A Ruel
2012/01/31 01:15:25
result = result or []
?
szager
2012/01/31 06:47:39
Obsolete now.
| |
| 592 if not self.should_process or not self.recursion_limit: | 610 if not self.should_process or not self.recursion_limit: |
| 593 # Don't run the hook when it is above recursion_limit. | 611 # Don't run the hook when it is above recursion_limit. |
| 594 return | 612 return |
| 595 # If "--force" was specified, run all hooks regardless of what files have | 613 # If "--force" was specified, run all hooks regardless of what files have |
| 596 # changed. | 614 # changed. |
| 597 if self.deps_hooks: | 615 if self.deps_hooks: |
| 598 # TODO(maruel): If the user is using git or git-svn, then we don't know | 616 # TODO(maruel): If the user is using git or git-svn, then we don't know |
| 599 # what files have changed so we always run all hooks. It'd be nice to fix | 617 # what files have changed so we always run all hooks. It'd be nice to fix |
| 600 # that. | 618 # that. |
| 601 if (options.force or | 619 if (options.force or |
| 602 isinstance(self.parsed_url, self.FileImpl) or | 620 isinstance(self.parsed_url, self.FileImpl) or |
| 603 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or | 621 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or |
| 604 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): | 622 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): |
| 605 for hook_dict in self.deps_hooks: | 623 for hook_dict in self.deps_hooks: |
| 606 self._RunHookAction(hook_dict, []) | 624 result.append(self.GetHookAction(hook_dict, [])) |
| 607 else: | 625 else: |
| 608 # Run hooks on the basis of whether the files from the gclient operation | 626 # Run hooks on the basis of whether the files from the gclient operation |
| 609 # match each hook's pattern. | 627 # match each hook's pattern. |
| 610 for hook_dict in self.deps_hooks: | 628 for hook_dict in self.deps_hooks: |
| 611 pattern = re.compile(hook_dict['pattern']) | 629 pattern = re.compile(hook_dict['pattern']) |
| 612 matching_file_list = [ | 630 matching_file_list = [ |
| 613 f for f in self.file_list_and_children if pattern.search(f) | 631 f for f in self.file_list_and_children if pattern.search(f) |
| 614 ] | 632 ] |
| 615 if matching_file_list: | 633 if matching_file_list: |
| 616 self._RunHookAction(hook_dict, matching_file_list) | 634 result.append(self.GetHookAction(hook_dict, matching_file_list)) |
| 617 for s in self.dependencies: | 635 for s in self.dependencies: |
| 618 s.RunHooksRecursively(options) | 636 s.GetHooks(options, result) |
| 637 return result | |
| 619 | 638 |
| 620 def _RunHookAction(self, hook_dict, matching_file_list): | 639 def RunHooksRecursively(self, options): |
| 621 """Runs the action from a single hook.""" | 640 assert self.hooks_ran == False |
| 622 # A single DEPS file can specify multiple hooks so this function can be | |
| 623 # called multiple times on a single Dependency. | |
| 624 #assert self.hooks_ran == False | |
| 625 self._hooks_ran = True | 641 self._hooks_ran = True |
| 626 logging.debug(hook_dict) | 642 for hook in self.GetHooks(options): |
| 627 logging.debug(matching_file_list) | 643 try: |
| 628 command = hook_dict['action'][:] | 644 gclient_utils.CheckCallAndFilterAndHeader( |
| 629 if command[0] == 'python': | 645 hook, cwd=self.root.root_dir, always=True) |
| 630 # If the hook specified "python" as the first item, the action is a | 646 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 631 # Python script. Run it by starting a new copy of the same | 647 # Use a discrete exit status code of 2 to indicate that a hook action |
| 632 # interpreter. | 648 # failed. Users of this script may wish to treat hook action failures |
| 633 command[0] = sys.executable | 649 # differently from VC failures. |
| 634 | 650 print >> sys.stderr, 'Error: %s' % str(e) |
| 635 if '$matching_files' in command: | 651 sys.exit(2) |
| 636 splice_index = command.index('$matching_files') | |
| 637 command[splice_index:splice_index + 1] = matching_file_list | |
| 638 | |
| 639 try: | |
| 640 gclient_utils.CheckCallAndFilterAndHeader( | |
| 641 command, cwd=self.root.root_dir, always=True) | |
| 642 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | |
| 643 # Use a discrete exit status code of 2 to indicate that a hook action | |
| 644 # failed. Users of this script may wish to treat hook action failures | |
| 645 # differently from VC failures. | |
| 646 print >> sys.stderr, 'Error: %s' % str(e) | |
| 647 sys.exit(2) | |
| 648 | 652 |
| 649 def subtree(self, include_all): | 653 def subtree(self, include_all): |
| 650 """Breadth first recursion excluding root node.""" | 654 """Breadth first recursion excluding root node.""" |
| 651 dependencies = self.dependencies | 655 dependencies = self.dependencies |
| 652 for d in dependencies: | 656 for d in dependencies: |
| 653 if d.should_process or include_all: | 657 if d.should_process or include_all: |
| 654 yield d | 658 yield d |
| 655 for d in dependencies: | 659 for d in dependencies: |
| 656 for i in d.subtree(include_all): | 660 for i in d.subtree(include_all): |
| 657 yield i | 661 yield i |
| (...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1416 'version of all repositories to reproduce the tree, ' | 1420 'version of all repositories to reproduce the tree, ' |
| 1417 'implies -a') | 1421 'implies -a') |
| 1418 (options, args) = parser.parse_args(args) | 1422 (options, args) = parser.parse_args(args) |
| 1419 client = GClient.LoadCurrentConfig(options) | 1423 client = GClient.LoadCurrentConfig(options) |
| 1420 if not client: | 1424 if not client: |
| 1421 raise gclient_utils.Error('client not configured; see \'gclient config\'') | 1425 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| 1422 client.PrintRevInfo() | 1426 client.PrintRevInfo() |
| 1423 return 0 | 1427 return 0 |
| 1424 | 1428 |
| 1425 | 1429 |
| 1430 def CMDhookinfo(parser, args): | |
| 1431 """Output the hooks that would be run by `gclient runhooks`""" | |
| 1432 (options, args) = parser.parse_args(args) | |
| 1433 client = GClient.LoadCurrentConfig(options) | |
| 1434 if not client: | |
| 1435 raise gclient_utils.Error('client not configured; see \'gclient config\'') | |
| 1436 work_queue = gclient_utils.ExecutionQueue(options.jobs, None) | |
| 1437 for s in client.dependencies: | |
| 1438 work_queue.enqueue(s) | |
| 1439 work_queue.flush({}, None, [], options=options) | |
| 1440 print client.GetHooks(options) | |
|
M-A Ruel
2012/01/31 01:15:25
for hook in client.GetHooks(options):
print ' '.
szager
2012/01/31 06:47:39
I'd like the output to be parse-able by python, so
| |
| 1441 return 0 | |
| 1442 | |
| 1443 | |
| 1426 def Command(name): | 1444 def Command(name): |
| 1427 return getattr(sys.modules[__name__], 'CMD' + name, None) | 1445 return getattr(sys.modules[__name__], 'CMD' + name, None) |
| 1428 | 1446 |
| 1429 | 1447 |
| 1430 def CMDhelp(parser, args): | 1448 def CMDhelp(parser, args): |
| 1431 """Prints list of commands or help for a specific command.""" | 1449 """Prints list of commands or help for a specific command.""" |
| 1432 (_, args) = parser.parse_args(args) | 1450 (_, args) = parser.parse_args(args) |
| 1433 if len(args) == 1: | 1451 if len(args) == 1: |
| 1434 return Main(args + ['--help']) | 1452 return Main(args + ['--help']) |
| 1435 parser.print_help() | 1453 parser.print_help() |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1532 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1550 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 1533 print >> sys.stderr, 'Error: %s' % str(e) | 1551 print >> sys.stderr, 'Error: %s' % str(e) |
| 1534 return 1 | 1552 return 1 |
| 1535 | 1553 |
| 1536 | 1554 |
| 1537 if '__main__' == __name__: | 1555 if '__main__' == __name__: |
| 1538 fix_encoding.fix_encoding() | 1556 fix_encoding.fix_encoding() |
| 1539 sys.exit(Main(sys.argv[1:])) | 1557 sys.exit(Main(sys.argv[1:])) |
| 1540 | 1558 |
| 1541 # vim: ts=2:sw=2:tw=80:et: | 1559 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |