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 |