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