| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 | 7 |
| 8 Files | 8 Files |
| 9 .gclient : Current client configuration, written by 'config' command. | 9 .gclient : Current client configuration, written by 'config' command. |
| 10 Format is a Python script defining 'solutions', a list whose | 10 Format is a Python script defining 'solutions', a list whose |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 # This is in both .gclient and DEPS files: | 156 # This is in both .gclient and DEPS files: |
| 157 self.url = url | 157 self.url = url |
| 158 | 158 |
| 159 # These are only set in .gclient and not in DEPS files. | 159 # These are only set in .gclient and not in DEPS files. |
| 160 # 'managed' determines whether or not this dependency is synced/updated by | 160 # 'managed' determines whether or not this dependency is synced/updated by |
| 161 # gclient after gclient checks it out initially. The difference between | 161 # gclient after gclient checks it out initially. The difference between |
| 162 # 'managed' and 'should_process' (defined below) is that the user specifies | 162 # 'managed' and 'should_process' (defined below) is that the user specifies |
| 163 # 'managed' via the --unmanaged command-line flag or a .gclient config, | 163 # 'managed' via the --unmanaged command-line flag or a .gclient config, |
| 164 # where 'should_process' is dynamically set by gclient if it goes over its | 164 # where 'should_process' is dynamically set by gclient if it goes over its |
| 165 # recursion limit and controls gclient's behavior so it does not misbehave. | 165 # recursion limit and controls gclient's behavior so it does not misbehave. |
| 166 self.managed = managed | 166 self._managed = managed |
| 167 self.custom_vars = custom_vars or {} | 167 self._custom_vars = custom_vars or {} |
| 168 self.custom_deps = custom_deps or {} | 168 self._custom_deps = custom_deps or {} |
| 169 self.deps_hooks = [] | 169 self.deps_hooks = [] |
| 170 | 170 |
| 171 # Calculates properties: | 171 # Calculates properties: |
| 172 self.parsed_url = None | 172 self.parsed_url = None |
| 173 self.dependencies = [] | 173 self.dependencies = [] |
| 174 # A cache of the files affected by the current operation, necessary for | 174 # A cache of the files affected by the current operation, necessary for |
| 175 # hooks. | 175 # hooks. |
| 176 self._file_list = [] | 176 self._file_list = [] |
| 177 # If it is not set to True, the dependency wasn't processed for its child | 177 # If it is not set to True, the dependency wasn't processed for its child |
| 178 # dependency, i.e. its DEPS wasn't read. | 178 # dependency, i.e. its DEPS wasn't read. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 # thus unsorted, while the .gclient format is a list thus sorted. | 219 # thus unsorted, while the .gclient format is a list thus sorted. |
| 220 # | 220 # |
| 221 # * _recursion_limit is hard coded 2 and there is no hope to change this | 221 # * _recursion_limit is hard coded 2 and there is no hope to change this |
| 222 # value. | 222 # value. |
| 223 # | 223 # |
| 224 # Interestingly enough, the following condition only works in the case we | 224 # Interestingly enough, the following condition only works in the case we |
| 225 # want: self is a 2nd level node. 3nd level node wouldn't need this since | 225 # want: self is a 2nd level node. 3nd level node wouldn't need this since |
| 226 # they already have their parent as a requirement. | 226 # they already have their parent as a requirement. |
| 227 root_deps = self.root.dependencies | 227 root_deps = self.root.dependencies |
| 228 if self.parent in root_deps: | 228 if self.parent in root_deps: |
| 229 for i in range(0, root_deps.index(self.parent)): | 229 for i in root_deps: |
| 230 value = root_deps[i] | 230 if i is self.parent: |
| 231 if value.name: | 231 break |
| 232 self._requirements.add(value.name) | 232 if i.name: |
| 233 self._requirements.add(i.name) |
| 233 | 234 |
| 234 if isinstance(self.url, self.FromImpl): | 235 if isinstance(self.url, self.FromImpl): |
| 235 self._requirements.add(self.url.module_name) | 236 self._requirements.add(self.url.module_name) |
| 236 | 237 |
| 237 if self.name and self.should_process: | 238 if self.name and self.should_process: |
| 238 def yield_full_tree(root): | 239 def yield_full_tree(root): |
| 239 """Depth-first recursion.""" | 240 """Depth-first recursion.""" |
| 240 yield root | 241 yield root |
| 241 for i in root.dependencies: | 242 for i in root.dependencies: |
| 242 for j in yield_full_tree(i): | 243 for j in yield_full_tree(i): |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 logging.debug(deps_content) | 351 logging.debug(deps_content) |
| 351 # Eval the content. | 352 # Eval the content. |
| 352 try: | 353 try: |
| 353 exec(deps_content, global_scope, local_scope) | 354 exec(deps_content, global_scope, local_scope) |
| 354 except SyntaxError, e: | 355 except SyntaxError, e: |
| 355 gclient_utils.SyntaxErrorToError(filepath, e) | 356 gclient_utils.SyntaxErrorToError(filepath, e) |
| 356 deps = local_scope.get('deps', {}) | 357 deps = local_scope.get('deps', {}) |
| 357 # load os specific dependencies if defined. these dependencies may | 358 # load os specific dependencies if defined. these dependencies may |
| 358 # override or extend the values defined by the 'deps' member. | 359 # override or extend the values defined by the 'deps' member. |
| 359 if 'deps_os' in local_scope: | 360 if 'deps_os' in local_scope: |
| 360 for deps_os_key in self.root.enforced_os: | 361 enforced_os = self.root.enforced_os |
| 362 for deps_os_key in enforced_os: |
| 361 os_deps = local_scope['deps_os'].get(deps_os_key, {}) | 363 os_deps = local_scope['deps_os'].get(deps_os_key, {}) |
| 362 if len(self.root.enforced_os) > 1: | 364 if len(enforced_os) > 1: |
| 363 # Ignore any conflict when including deps for more than one | 365 # Ignore any conflict when including deps for more than one |
| 364 # platform, so we collect the broadest set of dependencies | 366 # platform, so we collect the broadest set of dependencies |
| 365 # available. We may end up with the wrong revision of something for | 367 # available. We may end up with the wrong revision of something for |
| 366 # our platform, but this is the best we can do. | 368 # our platform, but this is the best we can do. |
| 367 deps.update([x for x in os_deps.items() if not x[0] in deps]) | 369 deps.update([x for x in os_deps.items() if not x[0] in deps]) |
| 368 else: | 370 else: |
| 369 deps.update(os_deps) | 371 deps.update(os_deps) |
| 370 | 372 |
| 371 self.deps_hooks.extend(local_scope.get('hooks', [])) | 373 self.deps_hooks.extend(local_scope.get('hooks', [])) |
| 372 | 374 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 561 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 560 # Use a discrete exit status code of 2 to indicate that a hook action | 562 # Use a discrete exit status code of 2 to indicate that a hook action |
| 561 # failed. Users of this script may wish to treat hook action failures | 563 # failed. Users of this script may wish to treat hook action failures |
| 562 # differently from VC failures. | 564 # differently from VC failures. |
| 563 print >> sys.stderr, 'Error: %s' % str(e) | 565 print >> sys.stderr, 'Error: %s' % str(e) |
| 564 sys.exit(2) | 566 sys.exit(2) |
| 565 | 567 |
| 566 def subtree(self, include_all): | 568 def subtree(self, include_all): |
| 567 """Breadth first""" | 569 """Breadth first""" |
| 568 result = [] | 570 result = [] |
| 569 for d in self.dependencies: | 571 dependencies = self.dependencies |
| 572 for d in dependencies: |
| 570 if d.should_process or include_all: | 573 if d.should_process or include_all: |
| 571 result.append(d) | 574 result.append(d) |
| 572 for d in self.dependencies: | 575 for d in dependencies: |
| 573 result.extend(d.subtree(include_all)) | 576 result.extend(d.subtree(include_all)) |
| 574 return result | 577 return result |
| 575 | 578 |
| 576 def get_custom_deps(self, name, url): | 579 def get_custom_deps(self, name, url): |
| 577 """Returns a custom deps if applicable.""" | 580 """Returns a custom deps if applicable.""" |
| 578 if self.parent: | 581 if self.parent: |
| 579 url = self.parent.get_custom_deps(name, url) | 582 url = self.parent.get_custom_deps(name, url) |
| 580 # None is a valid return value to disable a dependency. | 583 # None is a valid return value to disable a dependency. |
| 581 return self.custom_deps.get(name, url) | 584 return self.custom_deps.get(name, url) |
| 582 | 585 |
| 583 @property | 586 @property |
| 584 def recursion_limit(self): | 587 def recursion_limit(self): |
| 585 """Returns > 0 if this dependency is not too recursed to be processed.""" | 588 """Returns > 0 if this dependency is not too recursed to be processed. |
| 589 |
| 590 Immutable so no need to lock.""" |
| 586 return max(self.parent.recursion_limit - 1, 0) | 591 return max(self.parent.recursion_limit - 1, 0) |
| 587 | 592 |
| 588 @property | 593 @property |
| 589 def deps_file(self): | 594 def deps_file(self): |
| 595 """Immutable so no need to lock.""" |
| 590 return self._deps_file | 596 return self._deps_file |
| 591 | 597 |
| 592 @property | 598 @property |
| 599 def managed(self): |
| 600 """Immutable so no need to lock.""" |
| 601 return self._managed |
| 602 |
| 603 @property |
| 593 def safesync_url(self): | 604 def safesync_url(self): |
| 605 """Immutable so no need to lock.""" |
| 594 return self._safesync_url | 606 return self._safesync_url |
| 595 | 607 |
| 596 @property | 608 @property |
| 597 def should_process(self): | 609 def should_process(self): |
| 598 """True if this dependency should be processed, i.e. checked out.""" | 610 """True if this dependency should be processed, i.e. checked out.""" |
| 599 return self._should_process | 611 return self._should_process |
| 600 | 612 |
| 601 @property | 613 @property |
| 602 def parent(self): | 614 def parent(self): |
| 615 """Immutable so no need to lock.""" |
| 603 return self._parent | 616 return self._parent |
| 604 | 617 |
| 605 @property | 618 @property |
| 619 def custom_vars(self): |
| 620 """Immutable so no need to lock.""" |
| 621 return self._custom_vars.copy() |
| 622 |
| 623 @property |
| 624 def custom_deps(self): |
| 625 """Immutable so no need to lock.""" |
| 626 return self._custom_deps.copy() |
| 627 |
| 628 @property |
| 629 @gclient_utils.lockedmethod |
| 606 def file_list(self): | 630 def file_list(self): |
| 607 result = self._file_list[:] | 631 result = self._file_list[:] |
| 608 for d in self.dependencies: | 632 for d in self.dependencies: |
| 609 result.extend(d.file_list) | 633 result.extend(d.file_list) |
| 610 return tuple(result) | 634 return tuple(result) |
| 611 | 635 |
| 612 def __str__(self): | 636 def __str__(self): |
| 613 out = [] | 637 out = [] |
| 614 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', | 638 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', |
| 615 'custom_vars', 'deps_hooks', 'file_list', 'should_process', | 639 'custom_vars', 'deps_hooks', 'file_list', 'should_process', |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 enforced_os = options.deps_os.split(',') | 729 enforced_os = options.deps_os.split(',') |
| 706 else: | 730 else: |
| 707 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] | 731 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] |
| 708 if 'all' in enforced_os: | 732 if 'all' in enforced_os: |
| 709 enforced_os = self.DEPS_OS_CHOICES.itervalues() | 733 enforced_os = self.DEPS_OS_CHOICES.itervalues() |
| 710 self._enforced_os = tuple(set(enforced_os)) | 734 self._enforced_os = tuple(set(enforced_os)) |
| 711 self._root_dir = root_dir | 735 self._root_dir = root_dir |
| 712 self.config_content = None | 736 self.config_content = None |
| 713 | 737 |
| 714 def SetConfig(self, content): | 738 def SetConfig(self, content): |
| 715 assert self.dependencies == [] | 739 assert not self.dependencies |
| 716 config_dict = {} | 740 config_dict = {} |
| 717 self.config_content = content | 741 self.config_content = content |
| 718 try: | 742 try: |
| 719 exec(content, config_dict) | 743 exec(content, config_dict) |
| 720 except SyntaxError, e: | 744 except SyntaxError, e: |
| 721 gclient_utils.SyntaxErrorToError('.gclient', e) | 745 gclient_utils.SyntaxErrorToError('.gclient', e) |
| 722 for s in config_dict.get('solutions', []): | 746 for s in config_dict.get('solutions', []): |
| 723 try: | 747 try: |
| 724 tree = dict((d.name, d) for d in self.root.subtree(False)) | 748 tree = dict((d.name, d) for d in self.root.subtree(False)) |
| 725 if s['name'] in tree: | 749 if s['name'] in tree: |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1401 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1425 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 1402 print >> sys.stderr, 'Error: %s' % str(e) | 1426 print >> sys.stderr, 'Error: %s' % str(e) |
| 1403 return 1 | 1427 return 1 |
| 1404 | 1428 |
| 1405 | 1429 |
| 1406 if '__main__' == __name__: | 1430 if '__main__' == __name__: |
| 1407 fix_encoding.fix_encoding() | 1431 fix_encoding.fix_encoding() |
| 1408 sys.exit(Main(sys.argv[1:])) | 1432 sys.exit(Main(sys.argv[1:])) |
| 1409 | 1433 |
| 1410 # vim: ts=2:sw=2:tw=80:et: | 1434 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |