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 |