| 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 # Files | 7 # Files |
| 8 # .gclient : Current client configuration, written by 'config' command. | 8 # .gclient : Current client configuration, written by 'config' command. |
| 9 # Format is a Python script defining 'solutions', a list whose | 9 # Format is a Python script defining 'solutions', a list whose |
| 10 # entries each are maps binding the strings "name" and "url" | 10 # entries each are maps binding the strings "name" and "url" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 # | 48 # |
| 49 # Example: | 49 # Example: |
| 50 # hooks = [ | 50 # hooks = [ |
| 51 # { "pattern": "\\.(gif|jpe?g|pr0n|png)$", | 51 # { "pattern": "\\.(gif|jpe?g|pr0n|png)$", |
| 52 # "action": ["python", "image_indexer.py", "--all"]}, | 52 # "action": ["python", "image_indexer.py", "--all"]}, |
| 53 # { "pattern": ".", | 53 # { "pattern": ".", |
| 54 # "name": "gyp", | 54 # "name": "gyp", |
| 55 # "action": ["python", "src/build/gyp_chromium"]}, | 55 # "action": ["python", "src/build/gyp_chromium"]}, |
| 56 # ] | 56 # ] |
| 57 # | 57 # |
| 58 # Pre-DEPS Hooks | |
| 59 # DEPS files may optionally contain a list named "pre_deps_hooks". These are | |
| 60 # the same as normal hooks, except that they run before the DEPS are | |
| 61 # processed. Pre-DEPS run with "sync" and "revert" unless the --noprehooks | |
| 62 # flag is used. | |
| 63 # | |
| 64 # Specifying a target OS | 58 # Specifying a target OS |
| 65 # An optional key named "target_os" may be added to a gclient file to specify | 59 # An optional key named "target_os" may be added to a gclient file to specify |
| 66 # one or more additional operating systems that should be considered when | 60 # one or more additional operating systems that should be considered when |
| 67 # processing the deps_os dict of a DEPS file. | 61 # processing the deps_os dict of a DEPS file. |
| 68 # | 62 # |
| 69 # Example: | 63 # Example: |
| 70 # target_os = [ "android" ] | 64 # target_os = [ "android" ] |
| 71 # | 65 # |
| 72 # If the "target_os_only" key is also present and true, then *only* the | 66 # If the "target_os_only" key is also present and true, then *only* the |
| 73 # operating systems listed in "target_os" will be used. | 67 # operating systems listed in "target_os" will be used. |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, | 279 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, |
| 286 custom_vars, custom_hooks, deps_file, should_process): | 280 custom_vars, custom_hooks, deps_file, should_process): |
| 287 gclient_utils.WorkItem.__init__(self, name) | 281 gclient_utils.WorkItem.__init__(self, name) |
| 288 DependencySettings.__init__( | 282 DependencySettings.__init__( |
| 289 self, parent, url, safesync_url, managed, custom_deps, custom_vars, | 283 self, parent, url, safesync_url, managed, custom_deps, custom_vars, |
| 290 custom_hooks, deps_file, should_process) | 284 custom_hooks, deps_file, should_process) |
| 291 | 285 |
| 292 # This is in both .gclient and DEPS files: | 286 # This is in both .gclient and DEPS files: |
| 293 self._deps_hooks = [] | 287 self._deps_hooks = [] |
| 294 | 288 |
| 295 self._pre_deps_hooks = [] | |
| 296 | |
| 297 # Calculates properties: | 289 # Calculates properties: |
| 298 self._parsed_url = None | 290 self._parsed_url = None |
| 299 self._dependencies = [] | 291 self._dependencies = [] |
| 300 # A cache of the files affected by the current operation, necessary for | 292 # A cache of the files affected by the current operation, necessary for |
| 301 # hooks. | 293 # hooks. |
| 302 self._file_list = [] | 294 self._file_list = [] |
| 303 # If it is not set to True, the dependency wasn't processed for its child | 295 # If it is not set to True, the dependency wasn't processed for its child |
| 304 # dependency, i.e. its DEPS wasn't read. | 296 # dependency, i.e. its DEPS wasn't read. |
| 305 self._deps_parsed = False | 297 self._deps_parsed = False |
| 306 # This dependency has been processed, i.e. checked out | 298 # This dependency has been processed, i.e. checked out |
| 307 self._processed = False | 299 self._processed = False |
| 308 # This dependency had its pre-DEPS hooks run | |
| 309 self._pre_deps_hooks_ran = False | |
| 310 # This dependency had its hook run | 300 # This dependency had its hook run |
| 311 self._hooks_ran = False | 301 self._hooks_ran = False |
| 312 # This is the scm used to checkout self.url. It may be used by dependencies | 302 # This is the scm used to checkout self.url. It may be used by dependencies |
| 313 # to get the datetime of the revision we checked out. | 303 # to get the datetime of the revision we checked out. |
| 314 self._used_scm = None | 304 self._used_scm = None |
| 315 # The actual revision we ended up getting, or None if that information is | 305 # The actual revision we ended up getting, or None if that information is |
| 316 # unavailable | 306 # unavailable |
| 317 self._got_revision = None | 307 self._got_revision = None |
| 318 | 308 |
| 319 if not self.name and self.parent: | 309 if not self.name and self.parent: |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 hook_names_to_suppress = [c.get('name', '') for c in self.custom_hooks] | 541 hook_names_to_suppress = [c.get('name', '') for c in self.custom_hooks] |
| 552 for hook in local_scope.get('hooks', []): | 542 for hook in local_scope.get('hooks', []): |
| 553 if hook.get('name', '') not in hook_names_to_suppress: | 543 if hook.get('name', '') not in hook_names_to_suppress: |
| 554 hooks_to_run.append(hook) | 544 hooks_to_run.append(hook) |
| 555 | 545 |
| 556 # add the replacements and any additions | 546 # add the replacements and any additions |
| 557 for hook in self.custom_hooks: | 547 for hook in self.custom_hooks: |
| 558 if 'action' in hook: | 548 if 'action' in hook: |
| 559 hooks_to_run.append(hook) | 549 hooks_to_run.append(hook) |
| 560 | 550 |
| 561 self._pre_deps_hooks = [self.GetHookAction(hook, []) for hook in | |
| 562 local_scope.get('pre_deps_hooks', [])] | |
| 563 | |
| 564 self.add_dependencies_and_close(deps_to_add, hooks_to_run) | 551 self.add_dependencies_and_close(deps_to_add, hooks_to_run) |
| 565 logging.info('ParseDepsFile(%s) done' % self.name) | 552 logging.info('ParseDepsFile(%s) done' % self.name) |
| 566 | 553 |
| 567 def add_dependencies_and_close(self, deps_to_add, hooks): | 554 def add_dependencies_and_close(self, deps_to_add, hooks): |
| 568 """Adds the dependencies, hooks and mark the parsing as done.""" | 555 """Adds the dependencies, hooks and mark the parsing as done.""" |
| 569 for dep in deps_to_add: | 556 for dep in deps_to_add: |
| 570 if dep.verify_validity(): | 557 if dep.verify_validity(): |
| 571 self.add_dependency(dep) | 558 self.add_dependency(dep) |
| 572 self._mark_as_parsed(hooks) | 559 self._mark_as_parsed(hooks) |
| 573 | 560 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 continue | 641 continue |
| 655 prefix = os.path.commonprefix( | 642 prefix = os.path.commonprefix( |
| 656 [self.root.root_dir.lower(), file_list[i].lower()]) | 643 [self.root.root_dir.lower(), file_list[i].lower()]) |
| 657 file_list[i] = file_list[i][len(prefix):] | 644 file_list[i] = file_list[i][len(prefix):] |
| 658 # Strip any leading path separators. | 645 # Strip any leading path separators. |
| 659 while file_list[i].startswith(('\\', '/')): | 646 while file_list[i].startswith(('\\', '/')): |
| 660 file_list[i] = file_list[i][1:] | 647 file_list[i] = file_list[i][1:] |
| 661 | 648 |
| 662 # Always parse the DEPS file. | 649 # Always parse the DEPS file. |
| 663 self.ParseDepsFile() | 650 self.ParseDepsFile() |
| 651 |
| 664 self._run_is_done(file_list or [], parsed_url) | 652 self._run_is_done(file_list or [], parsed_url) |
| 665 if command in ('update', 'revert') and not options.noprehooks: | |
| 666 self.RunPreDepsHooks() | |
| 667 | 653 |
| 668 if self.recursion_limit: | 654 if self.recursion_limit: |
| 669 # Parse the dependencies of this dependency. | 655 # Parse the dependencies of this dependency. |
| 670 for s in self.dependencies: | 656 for s in self.dependencies: |
| 671 work_queue.enqueue(s) | 657 work_queue.enqueue(s) |
| 672 | 658 |
| 673 if command == 'recurse': | 659 if command == 'recurse': |
| 674 if not isinstance(parsed_url, self.FileImpl): | 660 if not isinstance(parsed_url, self.FileImpl): |
| 675 # Skip file only checkout. | 661 # Skip file only checkout. |
| 676 scm = gclient_scm.GetScmName(parsed_url) | 662 scm = gclient_scm.GetScmName(parsed_url) |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 # failed. Users of this script may wish to treat hook action failures | 784 # failed. Users of this script may wish to treat hook action failures |
| 799 # differently from VC failures. | 785 # differently from VC failures. |
| 800 print >> sys.stderr, 'Error: %s' % str(e) | 786 print >> sys.stderr, 'Error: %s' % str(e) |
| 801 sys.exit(2) | 787 sys.exit(2) |
| 802 finally: | 788 finally: |
| 803 elapsed_time = time.time() - start_time | 789 elapsed_time = time.time() - start_time |
| 804 if elapsed_time > 10: | 790 if elapsed_time > 10: |
| 805 print "Hook '%s' took %.2f secs" % ( | 791 print "Hook '%s' took %.2f secs" % ( |
| 806 gclient_utils.CommandToStr(hook), elapsed_time) | 792 gclient_utils.CommandToStr(hook), elapsed_time) |
| 807 | 793 |
| 808 def RunPreDepsHooks(self): | |
| 809 assert self.processed | |
| 810 assert self.deps_parsed | |
| 811 assert not self.pre_deps_hooks_ran | |
| 812 assert not self.hooks_ran | |
| 813 for s in self.dependencies: | |
| 814 assert not s.processed | |
| 815 self._pre_deps_hooks_ran = True | |
| 816 for hook in self.pre_deps_hooks: | |
| 817 try: | |
| 818 start_time = time.time() | |
| 819 gclient_utils.CheckCallAndFilterAndHeader( | |
| 820 hook, cwd=self.root.root_dir, always=True) | |
| 821 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | |
| 822 # Use a discrete exit status code of 2 to indicate that a hook action | |
| 823 # failed. Users of this script may wish to treat hook action failures | |
| 824 # differently from VC failures. | |
| 825 print >> sys.stderr, 'Error: %s' % str(e) | |
| 826 sys.exit(2) | |
| 827 finally: | |
| 828 elapsed_time = time.time() - start_time | |
| 829 if elapsed_time > 10: | |
| 830 print "Hook '%s' took %.2f secs" % ( | |
| 831 gclient_utils.CommandToStr(hook), elapsed_time) | |
| 832 | |
| 833 | |
| 834 def subtree(self, include_all): | 794 def subtree(self, include_all): |
| 835 """Breadth first recursion excluding root node.""" | 795 """Breadth first recursion excluding root node.""" |
| 836 dependencies = self.dependencies | 796 dependencies = self.dependencies |
| 837 for d in dependencies: | 797 for d in dependencies: |
| 838 if d.should_process or include_all: | 798 if d.should_process or include_all: |
| 839 yield d | 799 yield d |
| 840 for d in dependencies: | 800 for d in dependencies: |
| 841 for i in d.subtree(include_all): | 801 for i in d.subtree(include_all): |
| 842 yield i | 802 yield i |
| 843 | 803 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 863 def dependencies(self): | 823 def dependencies(self): |
| 864 return tuple(self._dependencies) | 824 return tuple(self._dependencies) |
| 865 | 825 |
| 866 @property | 826 @property |
| 867 @gclient_utils.lockedmethod | 827 @gclient_utils.lockedmethod |
| 868 def deps_hooks(self): | 828 def deps_hooks(self): |
| 869 return tuple(self._deps_hooks) | 829 return tuple(self._deps_hooks) |
| 870 | 830 |
| 871 @property | 831 @property |
| 872 @gclient_utils.lockedmethod | 832 @gclient_utils.lockedmethod |
| 873 def pre_deps_hooks(self): | |
| 874 return tuple(self._pre_deps_hooks) | |
| 875 | |
| 876 @property | |
| 877 @gclient_utils.lockedmethod | |
| 878 def parsed_url(self): | 833 def parsed_url(self): |
| 879 return self._parsed_url | 834 return self._parsed_url |
| 880 | 835 |
| 881 @property | 836 @property |
| 882 @gclient_utils.lockedmethod | 837 @gclient_utils.lockedmethod |
| 883 def deps_parsed(self): | 838 def deps_parsed(self): |
| 884 """This is purely for debugging purposes. It's not used anywhere.""" | 839 """This is purely for debugging purposes. It's not used anywhere.""" |
| 885 return self._deps_parsed | 840 return self._deps_parsed |
| 886 | 841 |
| 887 @property | 842 @property |
| 888 @gclient_utils.lockedmethod | 843 @gclient_utils.lockedmethod |
| 889 def processed(self): | 844 def processed(self): |
| 890 return self._processed | 845 return self._processed |
| 891 | 846 |
| 892 @property | 847 @property |
| 893 @gclient_utils.lockedmethod | 848 @gclient_utils.lockedmethod |
| 894 def pre_deps_hooks_ran(self): | |
| 895 return self._pre_deps_hooks_ran | |
| 896 | |
| 897 @property | |
| 898 @gclient_utils.lockedmethod | |
| 899 def hooks_ran(self): | 849 def hooks_ran(self): |
| 900 return self._hooks_ran | 850 return self._hooks_ran |
| 901 | 851 |
| 902 @property | 852 @property |
| 903 @gclient_utils.lockedmethod | 853 @gclient_utils.lockedmethod |
| 904 def file_list(self): | 854 def file_list(self): |
| 905 return tuple(self._file_list) | 855 return tuple(self._file_list) |
| 906 | 856 |
| 907 @property | 857 @property |
| 908 def used_scm(self): | 858 def used_scm(self): |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1598 } | 1548 } |
| 1599 } | 1549 } |
| 1600 } | 1550 } |
| 1601 """) | 1551 """) |
| 1602 def CMDsync(parser, args): | 1552 def CMDsync(parser, args): |
| 1603 """Checkout/update all modules.""" | 1553 """Checkout/update all modules.""" |
| 1604 parser.add_option('-f', '--force', action='store_true', | 1554 parser.add_option('-f', '--force', action='store_true', |
| 1605 help='force update even for unchanged modules') | 1555 help='force update even for unchanged modules') |
| 1606 parser.add_option('-n', '--nohooks', action='store_true', | 1556 parser.add_option('-n', '--nohooks', action='store_true', |
| 1607 help='don\'t run hooks after the update is complete') | 1557 help='don\'t run hooks after the update is complete') |
| 1608 parser.add_option('-p', '--noprehooks', action='store_true', | |
| 1609 help='don\'t run pre-DEPS hooks', default=False) | |
| 1610 parser.add_option('-r', '--revision', action='append', | 1558 parser.add_option('-r', '--revision', action='append', |
| 1611 dest='revisions', metavar='REV', default=[], | 1559 dest='revisions', metavar='REV', default=[], |
| 1612 help='Enforces revision/hash for the solutions with the ' | 1560 help='Enforces revision/hash for the solutions with the ' |
| 1613 'format src@rev. The src@ part is optional and can be ' | 1561 'format src@rev. The src@ part is optional and can be ' |
| 1614 'skipped. -r can be used multiple times when .gclient ' | 1562 'skipped. -r can be used multiple times when .gclient ' |
| 1615 'has multiple solutions configured and will work even ' | 1563 'has multiple solutions configured and will work even ' |
| 1616 'if the src@ part is skipped. Note that specifying ' | 1564 'if the src@ part is skipped. Note that specifying ' |
| 1617 '--revision means your safesync_url gets ignored.') | 1565 '--revision means your safesync_url gets ignored.') |
| 1618 parser.add_option('--with_branch_heads', action='store_true', | 1566 parser.add_option('--with_branch_heads', action='store_true', |
| 1619 help='Clone git "branch_heads" refspecs in addition to ' | 1567 help='Clone git "branch_heads" refspecs in addition to ' |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1705 """Reverts all modifications in every dependencies. | 1653 """Reverts all modifications in every dependencies. |
| 1706 | 1654 |
| 1707 That's the nuclear option to get back to a 'clean' state. It removes anything | 1655 That's the nuclear option to get back to a 'clean' state. It removes anything |
| 1708 that shows up in svn status.""" | 1656 that shows up in svn status.""" |
| 1709 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 1657 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| 1710 help='override deps for the specified (comma-separated) ' | 1658 help='override deps for the specified (comma-separated) ' |
| 1711 'platform(s); \'all\' will process all deps_os ' | 1659 'platform(s); \'all\' will process all deps_os ' |
| 1712 'references') | 1660 'references') |
| 1713 parser.add_option('-n', '--nohooks', action='store_true', | 1661 parser.add_option('-n', '--nohooks', action='store_true', |
| 1714 help='don\'t run hooks after the revert is complete') | 1662 help='don\'t run hooks after the revert is complete') |
| 1715 parser.add_option('-p', '--noprehooks', action='store_true', | |
| 1716 help='don\'t run pre-DEPS hooks', default=False) | |
| 1717 parser.add_option('--upstream', action='store_true', | 1663 parser.add_option('--upstream', action='store_true', |
| 1718 help='Make repo state match upstream branch.') | 1664 help='Make repo state match upstream branch.') |
| 1719 (options, args) = parser.parse_args(args) | 1665 (options, args) = parser.parse_args(args) |
| 1720 # --force is implied. | 1666 # --force is implied. |
| 1721 options.force = True | 1667 options.force = True |
| 1722 options.reset = False | 1668 options.reset = False |
| 1723 options.delete_unversioned_trees = False | 1669 options.delete_unversioned_trees = False |
| 1724 client = GClient.LoadCurrentConfig(options) | 1670 client = GClient.LoadCurrentConfig(options) |
| 1725 if not client: | 1671 if not client: |
| 1726 raise gclient_utils.Error('client not configured; see \'gclient config\'') | 1672 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1840 self.error('--jobs must be 1 or higher') | 1786 self.error('--jobs must be 1 or higher') |
| 1841 | 1787 |
| 1842 # These hacks need to die. | 1788 # These hacks need to die. |
| 1843 if not hasattr(options, 'revisions'): | 1789 if not hasattr(options, 'revisions'): |
| 1844 # GClient.RunOnDeps expects it even if not applicable. | 1790 # GClient.RunOnDeps expects it even if not applicable. |
| 1845 options.revisions = [] | 1791 options.revisions = [] |
| 1846 if not hasattr(options, 'head'): | 1792 if not hasattr(options, 'head'): |
| 1847 options.head = None | 1793 options.head = None |
| 1848 if not hasattr(options, 'nohooks'): | 1794 if not hasattr(options, 'nohooks'): |
| 1849 options.nohooks = True | 1795 options.nohooks = True |
| 1850 if not hasattr(options, 'noprehooks'): | |
| 1851 options.noprehooks = True | |
| 1852 if not hasattr(options, 'deps_os'): | 1796 if not hasattr(options, 'deps_os'): |
| 1853 options.deps_os = None | 1797 options.deps_os = None |
| 1854 if not hasattr(options, 'manually_grab_svn_rev'): | 1798 if not hasattr(options, 'manually_grab_svn_rev'): |
| 1855 options.manually_grab_svn_rev = None | 1799 options.manually_grab_svn_rev = None |
| 1856 if not hasattr(options, 'force'): | 1800 if not hasattr(options, 'force'): |
| 1857 options.force = None | 1801 options.force = None |
| 1858 return (options, args) | 1802 return (options, args) |
| 1859 | 1803 |
| 1860 | 1804 |
| 1861 def disable_buffering(): | 1805 def disable_buffering(): |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1889 raise | 1833 raise |
| 1890 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1834 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 1891 print >> sys.stderr, 'Error: %s' % str(e) | 1835 print >> sys.stderr, 'Error: %s' % str(e) |
| 1892 return 1 | 1836 return 1 |
| 1893 | 1837 |
| 1894 | 1838 |
| 1895 if '__main__' == __name__: | 1839 if '__main__' == __name__: |
| 1896 sys.exit(Main(sys.argv[1:])) | 1840 sys.exit(Main(sys.argv[1:])) |
| 1897 | 1841 |
| 1898 # vim: ts=2:sw=2:tw=80:et: | 1842 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |