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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 return self._custom_vars[var_name] | 207 return self._custom_vars[var_name] |
208 elif var_name in self._local_scope.get("vars", {}): | 208 elif var_name in self._local_scope.get("vars", {}): |
209 return self._local_scope["vars"][var_name] | 209 return self._local_scope["vars"][var_name] |
210 raise gclient_utils.Error("Var is not defined: %s" % var_name) | 210 raise gclient_utils.Error("Var is not defined: %s" % var_name) |
211 | 211 |
212 | 212 |
213 class DependencySettings(GClientKeywords): | 213 class DependencySettings(GClientKeywords): |
214 """Immutable configuration settings.""" | 214 """Immutable configuration settings.""" |
215 def __init__( | 215 def __init__( |
216 self, parent, url, safesync_url, managed, custom_deps, custom_vars, | 216 self, parent, url, safesync_url, managed, custom_deps, custom_vars, |
217 custom_hooks, deps_file, should_process): | 217 custom_hooks, deps_file, should_process, relative): |
218 GClientKeywords.__init__(self) | 218 GClientKeywords.__init__(self) |
219 | 219 |
220 # These are not mutable: | 220 # These are not mutable: |
221 self._parent = parent | 221 self._parent = parent |
222 self._safesync_url = safesync_url | 222 self._safesync_url = safesync_url |
223 self._deps_file = deps_file | 223 self._deps_file = deps_file |
224 self._url = url | 224 self._url = url |
225 # 'managed' determines whether or not this dependency is synced/updated by | 225 # 'managed' determines whether or not this dependency is synced/updated by |
226 # gclient after gclient checks it out initially. The difference between | 226 # gclient after gclient checks it out initially. The difference between |
227 # 'managed' and 'should_process' is that the user specifies 'managed' via | 227 # 'managed' and 'should_process' is that the user specifies 'managed' via |
228 # the --unmanaged command-line flag or a .gclient config, where | 228 # the --unmanaged command-line flag or a .gclient config, where |
229 # 'should_process' is dynamically set by gclient if it goes over its | 229 # 'should_process' is dynamically set by gclient if it goes over its |
230 # recursion limit and controls gclient's behavior so it does not misbehave. | 230 # recursion limit and controls gclient's behavior so it does not misbehave. |
231 self._managed = managed | 231 self._managed = managed |
232 self._should_process = should_process | 232 self._should_process = should_process |
| 233 # If this is a recursed-upon sub-dependency, and the parent has |
| 234 # use_relative_paths set, then this dependency should check out its own |
| 235 # dependencies relative to that parent's path for this, rather than |
| 236 # relative to the .gclient file. |
| 237 self._relative = relative |
233 # This is a mutable value which has the list of 'target_os' OSes listed in | 238 # This is a mutable value which has the list of 'target_os' OSes listed in |
234 # the current deps file. | 239 # the current deps file. |
235 self.local_target_os = None | 240 self.local_target_os = None |
236 | 241 |
237 # These are only set in .gclient and not in DEPS files. | 242 # These are only set in .gclient and not in DEPS files. |
238 self._custom_vars = custom_vars or {} | 243 self._custom_vars = custom_vars or {} |
239 self._custom_deps = custom_deps or {} | 244 self._custom_deps = custom_deps or {} |
240 self._custom_hooks = custom_hooks or [] | 245 self._custom_hooks = custom_hooks or [] |
241 | 246 |
242 # TODO(iannucci): Remove this when all masters are correctly substituting | 247 # TODO(iannucci): Remove this when all masters are correctly substituting |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 if self.parent: | 323 if self.parent: |
319 url = self.parent.get_custom_deps(name, url) | 324 url = self.parent.get_custom_deps(name, url) |
320 # None is a valid return value to disable a dependency. | 325 # None is a valid return value to disable a dependency. |
321 return self.custom_deps.get(name, url) | 326 return self.custom_deps.get(name, url) |
322 | 327 |
323 | 328 |
324 class Dependency(gclient_utils.WorkItem, DependencySettings): | 329 class Dependency(gclient_utils.WorkItem, DependencySettings): |
325 """Object that represents a dependency checkout.""" | 330 """Object that represents a dependency checkout.""" |
326 | 331 |
327 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, | 332 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, |
328 custom_vars, custom_hooks, deps_file, should_process): | 333 custom_vars, custom_hooks, deps_file, should_process, |
| 334 relative): |
329 gclient_utils.WorkItem.__init__(self, name) | 335 gclient_utils.WorkItem.__init__(self, name) |
330 DependencySettings.__init__( | 336 DependencySettings.__init__( |
331 self, parent, url, safesync_url, managed, custom_deps, custom_vars, | 337 self, parent, url, safesync_url, managed, custom_deps, custom_vars, |
332 custom_hooks, deps_file, should_process) | 338 custom_hooks, deps_file, should_process, relative) |
333 | 339 |
334 # This is in both .gclient and DEPS files: | 340 # This is in both .gclient and DEPS files: |
335 self._deps_hooks = [] | 341 self._deps_hooks = [] |
336 | 342 |
337 self._pre_deps_hooks = [] | 343 self._pre_deps_hooks = [] |
338 | 344 |
339 # Calculates properties: | 345 # Calculates properties: |
340 self._parsed_url = None | 346 self._parsed_url = None |
341 self._dependencies = [] | 347 self._dependencies = [] |
342 # A cache of the files affected by the current operation, necessary for | 348 # A cache of the files affected by the current operation, necessary for |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 # If a line is in custom_deps, but not in the solution, we want to append | 685 # If a line is in custom_deps, but not in the solution, we want to append |
680 # this line to the solution. | 686 # this line to the solution. |
681 for d in self.custom_deps: | 687 for d in self.custom_deps: |
682 if d not in deps: | 688 if d not in deps: |
683 deps[d] = self.custom_deps[d] | 689 deps[d] = self.custom_deps[d] |
684 | 690 |
685 # If use_relative_paths is set in the DEPS file, regenerate | 691 # If use_relative_paths is set in the DEPS file, regenerate |
686 # the dictionary using paths relative to the directory containing | 692 # the dictionary using paths relative to the directory containing |
687 # the DEPS file. Also update recursedeps if use_relative_paths is | 693 # the DEPS file. Also update recursedeps if use_relative_paths is |
688 # enabled. | 694 # enabled. |
| 695 # If the deps file doesn't set use_relative_paths, but the parent did |
| 696 # (and therefore set self.relative on this Dependency object), then we |
| 697 # want to modify the deps and recursedeps by prepending the parent |
| 698 # directory of this dependency. |
689 use_relative_paths = local_scope.get('use_relative_paths', False) | 699 use_relative_paths = local_scope.get('use_relative_paths', False) |
| 700 rel_prefix = None |
690 if use_relative_paths: | 701 if use_relative_paths: |
| 702 rel_prefix = self.name |
| 703 elif self._relative: |
| 704 rel_prefix = os.path.dirname(self.name) |
| 705 if rel_prefix: |
691 logging.warning('use_relative_paths enabled.') | 706 logging.warning('use_relative_paths enabled.') |
692 rel_deps = {} | 707 rel_deps = {} |
693 for d, url in deps.items(): | 708 for d, url in deps.items(): |
694 # normpath is required to allow DEPS to use .. in their | 709 # normpath is required to allow DEPS to use .. in their |
695 # dependency local path. | 710 # dependency local path. |
696 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url | 711 rel_deps[os.path.normpath(os.path.join(rel_prefix, d))] = url |
697 logging.warning('Updating deps by prepending %s.', self.name) | 712 logging.warning('Updating deps by prepending %s.', rel_prefix) |
698 deps = rel_deps | 713 deps = rel_deps |
699 | 714 |
700 # Update recursedeps if it's set. | 715 # Update recursedeps if it's set. |
701 if self.recursedeps is not None: | 716 if self.recursedeps is not None: |
702 logging.warning('Updating recursedeps by prepending %s.', self.name) | 717 logging.warning('Updating recursedeps by prepending %s.', rel_prefix) |
703 rel_deps = {} | 718 rel_deps = {} |
704 for depname, options in self.recursedeps.iteritems(): | 719 for depname, options in self.recursedeps.iteritems(): |
705 rel_deps[os.path.normpath(os.path.join(self.name, depname))] = options | 720 rel_deps[ |
| 721 os.path.normpath(os.path.join(rel_prefix, depname))] = options |
706 self.recursedeps = rel_deps | 722 self.recursedeps = rel_deps |
707 | 723 |
| 724 |
708 if 'allowed_hosts' in local_scope: | 725 if 'allowed_hosts' in local_scope: |
709 try: | 726 try: |
710 self._allowed_hosts = frozenset(local_scope.get('allowed_hosts')) | 727 self._allowed_hosts = frozenset(local_scope.get('allowed_hosts')) |
711 except TypeError: # raised if non-iterable | 728 except TypeError: # raised if non-iterable |
712 pass | 729 pass |
713 if not self._allowed_hosts: | 730 if not self._allowed_hosts: |
714 logging.warning("allowed_hosts is specified but empty %s", | 731 logging.warning("allowed_hosts is specified but empty %s", |
715 self._allowed_hosts) | 732 self._allowed_hosts) |
716 raise gclient_utils.Error( | 733 raise gclient_utils.Error( |
717 'ParseDepsFile(%s): allowed_hosts must be absent ' | 734 'ParseDepsFile(%s): allowed_hosts must be absent ' |
718 'or a non-empty iterable' % self.name) | 735 'or a non-empty iterable' % self.name) |
719 | 736 |
720 # Convert the deps into real Dependency. | 737 # Convert the deps into real Dependency. |
721 deps_to_add = [] | 738 deps_to_add = [] |
722 for name, url in deps.iteritems(): | 739 for name, url in deps.iteritems(): |
723 should_process = self.recursion_limit and self.should_process | 740 should_process = self.recursion_limit and self.should_process |
724 deps_file = self.deps_file | 741 deps_file = self.deps_file |
725 if self.recursedeps is not None: | 742 if self.recursedeps is not None: |
726 ent = self.recursedeps.get(name) | 743 ent = self.recursedeps.get(name) |
727 if ent is not None: | 744 if ent is not None: |
728 deps_file = ent['deps_file'] | 745 deps_file = ent['deps_file'] |
729 deps_to_add.append(Dependency( | 746 deps_to_add.append(Dependency( |
730 self, name, url, None, None, None, self.custom_vars, None, | 747 self, name, url, None, None, None, self.custom_vars, None, |
731 deps_file, should_process)) | 748 deps_file, should_process, use_relative_paths)) |
732 deps_to_add.sort(key=lambda x: x.name) | 749 deps_to_add.sort(key=lambda x: x.name) |
733 | 750 |
734 # override named sets of hooks by the custom hooks | 751 # override named sets of hooks by the custom hooks |
735 hooks_to_run = [] | 752 hooks_to_run = [] |
736 hook_names_to_suppress = [c.get('name', '') for c in self.custom_hooks] | 753 hook_names_to_suppress = [c.get('name', '') for c in self.custom_hooks] |
737 for hook in local_scope.get('hooks', []): | 754 for hook in local_scope.get('hooks', []): |
738 if hook.get('name', '') not in hook_names_to_suppress: | 755 if hook.get('name', '') not in hook_names_to_suppress: |
739 hooks_to_run.append(hook) | 756 hooks_to_run.append(hook) |
740 | 757 |
741 # add the replacements and any additions | 758 # add the replacements and any additions |
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1210 # Snapshot generated with gclient revinfo --snapshot | 1227 # Snapshot generated with gclient revinfo --snapshot |
1211 solutions = [ | 1228 solutions = [ |
1212 %(solution_list)s] | 1229 %(solution_list)s] |
1213 """) | 1230 """) |
1214 | 1231 |
1215 def __init__(self, root_dir, options): | 1232 def __init__(self, root_dir, options): |
1216 # Do not change previous behavior. Only solution level and immediate DEPS | 1233 # Do not change previous behavior. Only solution level and immediate DEPS |
1217 # are processed. | 1234 # are processed. |
1218 self._recursion_limit = 2 | 1235 self._recursion_limit = 2 |
1219 Dependency.__init__(self, None, None, None, None, True, None, None, None, | 1236 Dependency.__init__(self, None, None, None, None, True, None, None, None, |
1220 'unused', True) | 1237 'unused', True, None) |
1221 self._options = options | 1238 self._options = options |
1222 if options.deps_os: | 1239 if options.deps_os: |
1223 enforced_os = options.deps_os.split(',') | 1240 enforced_os = options.deps_os.split(',') |
1224 else: | 1241 else: |
1225 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] | 1242 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] |
1226 if 'all' in enforced_os: | 1243 if 'all' in enforced_os: |
1227 enforced_os = self.DEPS_OS_CHOICES.itervalues() | 1244 enforced_os = self.DEPS_OS_CHOICES.itervalues() |
1228 self._enforced_os = tuple(set(enforced_os)) | 1245 self._enforced_os = tuple(set(enforced_os)) |
1229 self._root_dir = root_dir | 1246 self._root_dir = root_dir |
1230 self.config_content = None | 1247 self.config_content = None |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1301 for s in config_dict.get('solutions', []): | 1318 for s in config_dict.get('solutions', []): |
1302 try: | 1319 try: |
1303 deps_to_add.append(Dependency( | 1320 deps_to_add.append(Dependency( |
1304 self, s['name'], s['url'], | 1321 self, s['name'], s['url'], |
1305 s.get('safesync_url', None), | 1322 s.get('safesync_url', None), |
1306 s.get('managed', True), | 1323 s.get('managed', True), |
1307 s.get('custom_deps', {}), | 1324 s.get('custom_deps', {}), |
1308 s.get('custom_vars', {}), | 1325 s.get('custom_vars', {}), |
1309 s.get('custom_hooks', []), | 1326 s.get('custom_hooks', []), |
1310 s.get('deps_file', 'DEPS'), | 1327 s.get('deps_file', 'DEPS'), |
1311 True)) | 1328 True, |
| 1329 None)) |
1312 except KeyError: | 1330 except KeyError: |
1313 raise gclient_utils.Error('Invalid .gclient file. Solution is ' | 1331 raise gclient_utils.Error('Invalid .gclient file. Solution is ' |
1314 'incomplete: %s' % s) | 1332 'incomplete: %s' % s) |
1315 self.add_dependencies_and_close(deps_to_add, config_dict.get('hooks', [])) | 1333 self.add_dependencies_and_close(deps_to_add, config_dict.get('hooks', [])) |
1316 logging.info('SetConfig() done') | 1334 logging.info('SetConfig() done') |
1317 | 1335 |
1318 def SaveConfig(self): | 1336 def SaveConfig(self): |
1319 gclient_utils.FileWrite(os.path.join(self.root_dir, | 1337 gclient_utils.FileWrite(os.path.join(self.root_dir, |
1320 self._options.config_filename), | 1338 self._options.config_filename), |
1321 self.config_content) | 1339 self.config_content) |
(...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2356 | 2374 |
2357 | 2375 |
2358 if '__main__' == __name__: | 2376 if '__main__' == __name__: |
2359 try: | 2377 try: |
2360 sys.exit(main(sys.argv[1:])) | 2378 sys.exit(main(sys.argv[1:])) |
2361 except KeyboardInterrupt: | 2379 except KeyboardInterrupt: |
2362 sys.stderr.write('interrupted\n') | 2380 sys.stderr.write('interrupted\n') |
2363 sys.exit(1) | 2381 sys.exit(1) |
2364 | 2382 |
2365 # vim: ts=2:sw=2:tw=80:et: | 2383 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |