| 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 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 self._deps_hooks = [] | 335 self._deps_hooks = [] |
| 336 | 336 |
| 337 self._pre_deps_hooks = [] | 337 self._pre_deps_hooks = [] |
| 338 | 338 |
| 339 # Calculates properties: | 339 # Calculates properties: |
| 340 self._parsed_url = None | 340 self._parsed_url = None |
| 341 self._dependencies = [] | 341 self._dependencies = [] |
| 342 # A cache of the files affected by the current operation, necessary for | 342 # A cache of the files affected by the current operation, necessary for |
| 343 # hooks. | 343 # hooks. |
| 344 self._file_list = [] | 344 self._file_list = [] |
| 345 # List of host names from which dependencies are allowed. |
| 346 # Default is an empty set, meaning unspecified in DEPS file, and hence all |
| 347 # hosts will be allowed. Non-empty set means whitelist of hosts. |
| 348 # allowed_hosts var is scoped to its DEPS file, and so it isn't recursive. |
| 349 self._allowed_hosts = frozenset() |
| 345 # If it is not set to True, the dependency wasn't processed for its child | 350 # If it is not set to True, the dependency wasn't processed for its child |
| 346 # dependency, i.e. its DEPS wasn't read. | 351 # dependency, i.e. its DEPS wasn't read. |
| 347 self._deps_parsed = False | 352 self._deps_parsed = False |
| 348 # This dependency has been processed, i.e. checked out | 353 # This dependency has been processed, i.e. checked out |
| 349 self._processed = False | 354 self._processed = False |
| 350 # This dependency had its pre-DEPS hooks run | 355 # This dependency had its pre-DEPS hooks run |
| 351 self._pre_deps_hooks_ran = False | 356 self._pre_deps_hooks_ran = False |
| 352 # This dependency had its hook run | 357 # This dependency had its hook run |
| 353 self._hooks_ran = False | 358 self._hooks_ran = False |
| 354 # This is the scm used to checkout self.url. It may be used by dependencies | 359 # This is the scm used to checkout self.url. It may be used by dependencies |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 deps = rel_deps | 685 deps = rel_deps |
| 681 | 686 |
| 682 # Update recursedeps if it's set. | 687 # Update recursedeps if it's set. |
| 683 if self.recursedeps is not None: | 688 if self.recursedeps is not None: |
| 684 logging.warning('Updating recursedeps by prepending %s.', self.name) | 689 logging.warning('Updating recursedeps by prepending %s.', self.name) |
| 685 rel_deps = set() | 690 rel_deps = set() |
| 686 for d in self.recursedeps: | 691 for d in self.recursedeps: |
| 687 rel_deps.add(os.path.normpath(os.path.join(self.name, d))) | 692 rel_deps.add(os.path.normpath(os.path.join(self.name, d))) |
| 688 self.recursedeps = rel_deps | 693 self.recursedeps = rel_deps |
| 689 | 694 |
| 695 if 'allowed_hosts' in local_scope: |
| 696 try: |
| 697 self._allowed_hosts = frozenset(local_scope.get('allowed_hosts')) |
| 698 except TypeError: # raised if non-iterable |
| 699 pass |
| 700 if not self._allowed_hosts: |
| 701 logging.warning("allowed_hosts is specified but empty %s", |
| 702 self._allowed_hosts) |
| 703 raise gclient_utils.Error( |
| 704 'ParseDepsFile(%s): allowed_hosts must be absent ' |
| 705 'or a non-empty iterable' % self.name) |
| 706 |
| 690 # Convert the deps into real Dependency. | 707 # Convert the deps into real Dependency. |
| 691 deps_to_add = [] | 708 deps_to_add = [] |
| 692 for name, url in deps.iteritems(): | 709 for name, url in deps.iteritems(): |
| 693 should_process = self.recursion_limit and self.should_process | 710 should_process = self.recursion_limit and self.should_process |
| 694 deps_to_add.append(Dependency( | 711 deps_to_add.append(Dependency( |
| 695 self, name, url, None, None, None, None, None, | 712 self, name, url, None, None, None, None, None, |
| 696 self.deps_file, should_process)) | 713 self.deps_file, should_process)) |
| 697 deps_to_add.sort(key=lambda x: x.name) | 714 deps_to_add.sort(key=lambda x: x.name) |
| 698 | 715 |
| 699 # override named sets of hooks by the custom hooks | 716 # override named sets of hooks by the custom hooks |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 'repository.' % options.revision) | 766 'repository.' % options.revision) |
| 750 else: | 767 else: |
| 751 parent_revision_date = self.parent.used_scm.GetRevisionDate( | 768 parent_revision_date = self.parent.used_scm.GetRevisionDate( |
| 752 options.revision) | 769 options.revision) |
| 753 options.revision = gclient_utils.MakeDateRevision( | 770 options.revision = gclient_utils.MakeDateRevision( |
| 754 parent_revision_date) | 771 parent_revision_date) |
| 755 if options.verbose: | 772 if options.verbose: |
| 756 print('Using parent\'s revision date %s since we are in a ' | 773 print('Using parent\'s revision date %s since we are in a ' |
| 757 'different repository.' % options.revision) | 774 'different repository.' % options.revision) |
| 758 | 775 |
| 776 def findDepsFromNotAllowedHosts(self): |
| 777 """Returns a list of depenecies from not allowed hosts. |
| 778 |
| 779 If allowed_hosts is not set, allows all hosts and returns empty list. |
| 780 """ |
| 781 if not self._allowed_hosts: |
| 782 return [] |
| 783 bad_deps = [] |
| 784 for dep in self._dependencies: |
| 785 if isinstance(dep.url, basestring): |
| 786 parsed_url = urlparse.urlparse(dep.url) |
| 787 if parsed_url.netloc and parsed_url.netloc not in self._allowed_hosts: |
| 788 bad_deps.append(dep) |
| 789 return bad_deps |
| 790 |
| 759 # Arguments number differs from overridden method | 791 # Arguments number differs from overridden method |
| 760 # pylint: disable=W0221 | 792 # pylint: disable=W0221 |
| 761 def run(self, revision_overrides, command, args, work_queue, options): | 793 def run(self, revision_overrides, command, args, work_queue, options): |
| 762 """Runs |command| then parse the DEPS file.""" | 794 """Runs |command| then parse the DEPS file.""" |
| 763 logging.info('Dependency(%s).run()' % self.name) | 795 logging.info('Dependency(%s).run()' % self.name) |
| 764 assert self._file_list == [] | 796 assert self._file_list == [] |
| 765 if not self.should_process: | 797 if not self.should_process: |
| 766 return | 798 return |
| 767 # When running runhooks, there's no need to consult the SCM. | 799 # When running runhooks, there's no need to consult the SCM. |
| 768 # All known hooks are expected to run unconditionally regardless of working | 800 # All known hooks are expected to run unconditionally regardless of working |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1046 def pre_deps_hooks_ran(self): | 1078 def pre_deps_hooks_ran(self): |
| 1047 return self._pre_deps_hooks_ran | 1079 return self._pre_deps_hooks_ran |
| 1048 | 1080 |
| 1049 @property | 1081 @property |
| 1050 @gclient_utils.lockedmethod | 1082 @gclient_utils.lockedmethod |
| 1051 def hooks_ran(self): | 1083 def hooks_ran(self): |
| 1052 return self._hooks_ran | 1084 return self._hooks_ran |
| 1053 | 1085 |
| 1054 @property | 1086 @property |
| 1055 @gclient_utils.lockedmethod | 1087 @gclient_utils.lockedmethod |
| 1088 def allowed_hosts(self): |
| 1089 return self._allowed_hosts |
| 1090 |
| 1091 @property |
| 1092 @gclient_utils.lockedmethod |
| 1056 def file_list(self): | 1093 def file_list(self): |
| 1057 return tuple(self._file_list) | 1094 return tuple(self._file_list) |
| 1058 | 1095 |
| 1059 @property | 1096 @property |
| 1060 def used_scm(self): | 1097 def used_scm(self): |
| 1061 """SCMWrapper instance for this dependency or None if not processed yet.""" | 1098 """SCMWrapper instance for this dependency or None if not processed yet.""" |
| 1062 return self._used_scm | 1099 return self._used_scm |
| 1063 | 1100 |
| 1064 @property | 1101 @property |
| 1065 @gclient_utils.lockedmethod | 1102 @gclient_utils.lockedmethod |
| 1066 def got_revision(self): | 1103 def got_revision(self): |
| 1067 return self._got_revision | 1104 return self._got_revision |
| 1068 | 1105 |
| 1069 @property | 1106 @property |
| 1070 def file_list_and_children(self): | 1107 def file_list_and_children(self): |
| 1071 result = list(self.file_list) | 1108 result = list(self.file_list) |
| 1072 for d in self.dependencies: | 1109 for d in self.dependencies: |
| 1073 result.extend(d.file_list_and_children) | 1110 result.extend(d.file_list_and_children) |
| 1074 return tuple(result) | 1111 return tuple(result) |
| 1075 | 1112 |
| 1076 def __str__(self): | 1113 def __str__(self): |
| 1077 out = [] | 1114 out = [] |
| 1078 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', | 1115 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', |
| 1079 'custom_vars', 'deps_hooks', 'file_list', 'should_process', | 1116 'custom_vars', 'deps_hooks', 'file_list', 'should_process', |
| 1080 'processed', 'hooks_ran', 'deps_parsed', 'requirements'): | 1117 'processed', 'hooks_ran', 'deps_parsed', 'requirements', |
| 1118 'allowed_hosts'): |
| 1081 # First try the native property if it exists. | 1119 # First try the native property if it exists. |
| 1082 if hasattr(self, '_' + i): | 1120 if hasattr(self, '_' + i): |
| 1083 value = getattr(self, '_' + i, False) | 1121 value = getattr(self, '_' + i, False) |
| 1084 else: | 1122 else: |
| 1085 value = getattr(self, i, False) | 1123 value = getattr(self, i, False) |
| 1086 if value: | 1124 if value: |
| 1087 out.append('%s: %s' % (i, value)) | 1125 out.append('%s: %s' % (i, value)) |
| 1088 | 1126 |
| 1089 for d in self.dependencies: | 1127 for d in self.dependencies: |
| 1090 out.extend([' ' + x for x in str(d).splitlines()]) | 1128 out.extend([' ' + x for x in str(d).splitlines()]) |
| (...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2079 (options, args) = parser.parse_args(args) | 2117 (options, args) = parser.parse_args(args) |
| 2080 options.force = True | 2118 options.force = True |
| 2081 client = GClient.LoadCurrentConfig(options) | 2119 client = GClient.LoadCurrentConfig(options) |
| 2082 if not client: | 2120 if not client: |
| 2083 raise gclient_utils.Error('client not configured; see \'gclient config\'') | 2121 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| 2084 client.RunOnDeps(None, []) | 2122 client.RunOnDeps(None, []) |
| 2085 print '; '.join(' '.join(hook) for hook in client.GetHooks(options)) | 2123 print '; '.join(' '.join(hook) for hook in client.GetHooks(options)) |
| 2086 return 0 | 2124 return 0 |
| 2087 | 2125 |
| 2088 | 2126 |
| 2127 def CMDverify(parser, args): |
| 2128 """Verifies the DEPS file deps are only from allowed_hosts.""" |
| 2129 (options, args) = parser.parse_args(args) |
| 2130 client = GClient.LoadCurrentConfig(options) |
| 2131 if not client: |
| 2132 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| 2133 client.RunOnDeps(None, []) |
| 2134 # Look at each first-level dependency of this gclient only. |
| 2135 for dep in client.dependencies: |
| 2136 bad_deps = dep.findDepsFromNotAllowedHosts() |
| 2137 if not bad_deps: |
| 2138 continue |
| 2139 print "There are deps from not allowed hosts in file %s" % dep.deps_file |
| 2140 for bad_dep in bad_deps: |
| 2141 print "\t%s at %s" % (bad_dep.name, bad_dep.url) |
| 2142 print "allowed_hosts:", ', '.join(dep.allowed_hosts) |
| 2143 sys.stdout.flush() |
| 2144 raise gclient_utils.Error( |
| 2145 'dependencies from disallowed hosts; check your DEPS file.') |
| 2146 return 0 |
| 2147 |
| 2089 class OptionParser(optparse.OptionParser): | 2148 class OptionParser(optparse.OptionParser): |
| 2090 gclientfile_default = os.environ.get('GCLIENT_FILE', '.gclient') | 2149 gclientfile_default = os.environ.get('GCLIENT_FILE', '.gclient') |
| 2091 | 2150 |
| 2092 def __init__(self, **kwargs): | 2151 def __init__(self, **kwargs): |
| 2093 optparse.OptionParser.__init__( | 2152 optparse.OptionParser.__init__( |
| 2094 self, version='%prog ' + __version__, **kwargs) | 2153 self, version='%prog ' + __version__, **kwargs) |
| 2095 | 2154 |
| 2096 # Some arm boards have issues with parallel sync. | 2155 # Some arm boards have issues with parallel sync. |
| 2097 if platform.machine().startswith('arm'): | 2156 if platform.machine().startswith('arm'): |
| 2098 jobs = 1 | 2157 jobs = 1 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2194 print >> sys.stderr, 'Error: %s' % str(e) | 2253 print >> sys.stderr, 'Error: %s' % str(e) |
| 2195 return 1 | 2254 return 1 |
| 2196 finally: | 2255 finally: |
| 2197 gclient_utils.PrintWarnings() | 2256 gclient_utils.PrintWarnings() |
| 2198 | 2257 |
| 2199 | 2258 |
| 2200 if '__main__' == __name__: | 2259 if '__main__' == __name__: |
| 2201 sys.exit(Main(sys.argv[1:])) | 2260 sys.exit(Main(sys.argv[1:])) |
| 2202 | 2261 |
| 2203 # vim: ts=2:sw=2:tw=80:et: | 2262 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |