| 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 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 def custom_deps(self): | 196 def custom_deps(self): |
| 197 """Immutable so no need to lock.""" | 197 """Immutable so no need to lock.""" |
| 198 return self._custom_deps.copy() | 198 return self._custom_deps.copy() |
| 199 | 199 |
| 200 | 200 |
| 201 class Dependency(GClientKeywords, gclient_utils.WorkItem, DependencySettings): | 201 class Dependency(GClientKeywords, gclient_utils.WorkItem, DependencySettings): |
| 202 """Object that represents a dependency checkout.""" | 202 """Object that represents a dependency checkout.""" |
| 203 | 203 |
| 204 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, | 204 def __init__(self, parent, name, url, safesync_url, managed, custom_deps, |
| 205 custom_vars, deps_file, should_process): | 205 custom_vars, deps_file, should_process): |
| 206 # Warning: this function can be called from any thread. Both | |
| 207 # self.dependencies and self.requirements are read and modified from | |
| 208 # multiple threads at the same time. Sad. | |
| 209 GClientKeywords.__init__(self) | 206 GClientKeywords.__init__(self) |
| 210 gclient_utils.WorkItem.__init__(self, name) | 207 gclient_utils.WorkItem.__init__(self, name) |
| 211 DependencySettings.__init__( | 208 DependencySettings.__init__( |
| 212 self, parent, safesync_url, managed, custom_deps, custom_vars, | 209 self, parent, safesync_url, managed, custom_deps, custom_vars, |
| 213 deps_file, should_process) | 210 deps_file, should_process) |
| 214 | 211 |
| 215 # This is in both .gclient and DEPS files: | 212 # This is in both .gclient and DEPS files: |
| 216 self.url = url | 213 self.url = url |
| 217 | 214 |
| 218 self.deps_hooks = [] | 215 self.deps_hooks = [] |
| 219 | 216 |
| 220 # Calculates properties: | 217 # Calculates properties: |
| 221 self.parsed_url = None | 218 self.parsed_url = None |
| 222 self.dependencies = [] | 219 self._dependencies = [] |
| 223 # A cache of the files affected by the current operation, necessary for | 220 # A cache of the files affected by the current operation, necessary for |
| 224 # hooks. | 221 # hooks. |
| 225 self._file_list = [] | 222 self._file_list = [] |
| 226 # If it is not set to True, the dependency wasn't processed for its child | 223 # If it is not set to True, the dependency wasn't processed for its child |
| 227 # dependency, i.e. its DEPS wasn't read. | 224 # dependency, i.e. its DEPS wasn't read. |
| 228 self.deps_parsed = False | 225 self.deps_parsed = False |
| 229 # This dependency has been processed, i.e. checked out | 226 # This dependency has been processed, i.e. checked out |
| 230 self.processed = False | 227 self.processed = False |
| 231 # This dependency had its hook run | 228 # This dependency had its hook run |
| 232 self.hooks_ran = False | 229 self.hooks_ran = False |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 if use_relative_paths: | 428 if use_relative_paths: |
| 432 rel_deps = {} | 429 rel_deps = {} |
| 433 for d, url in deps.items(): | 430 for d, url in deps.items(): |
| 434 # normpath is required to allow DEPS to use .. in their | 431 # normpath is required to allow DEPS to use .. in their |
| 435 # dependency local path. | 432 # dependency local path. |
| 436 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url | 433 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url |
| 437 deps = rel_deps | 434 deps = rel_deps |
| 438 | 435 |
| 439 # Convert the deps into real Dependency. | 436 # Convert the deps into real Dependency. |
| 440 for name, url in deps.iteritems(): | 437 for name, url in deps.iteritems(): |
| 441 if name in [s.name for s in self.dependencies]: | 438 if name in [s.name for s in self._dependencies]: |
| 442 raise gclient_utils.Error( | 439 raise gclient_utils.Error( |
| 443 'The same name "%s" appears multiple times in the deps section' % | 440 'The same name "%s" appears multiple times in the deps section' % |
| 444 name) | 441 name) |
| 445 should_process = self.recursion_limit and self.should_process | 442 should_process = self.recursion_limit and self.should_process |
| 446 if should_process: | 443 if should_process: |
| 447 tree = dict((d.name, d) for d in self.root.subtree(False)) | 444 tree = dict((d.name, d) for d in self.root.subtree(False)) |
| 448 if name in tree: | 445 if name in tree: |
| 449 if url == tree[name].url: | 446 if url == tree[name].url: |
| 450 logging.info('Won\'t process duplicate dependency %s' % tree[name]) | 447 logging.info('Won\'t process duplicate dependency %s' % tree[name]) |
| 451 # In theory we could keep it as a shadow of the other one. In | 448 # In theory we could keep it as a shadow of the other one. In |
| 452 # practice, simply ignore it. | 449 # practice, simply ignore it. |
| 453 #should_process = False | 450 #should_process = False |
| 454 continue | 451 continue |
| 455 else: | 452 else: |
| 456 raise gclient_utils.Error( | 453 raise gclient_utils.Error( |
| 457 'Dependency %s specified more than once:\n %s\nvs\n %s' % | 454 'Dependency %s specified more than once:\n %s\nvs\n %s' % |
| 458 (name, tree[name].hierarchy(), self.hierarchy())) | 455 (name, tree[name].hierarchy(), self.hierarchy())) |
| 459 self.dependencies.append(Dependency(self, name, url, None, None, None, | 456 self._dependencies.append( |
| 460 None, self.deps_file, should_process)) | 457 Dependency( |
| 458 self, name, url, None, None, None, None, |
| 459 self.deps_file, should_process)) |
| 461 logging.debug('Loaded: %s' % str(self)) | 460 logging.debug('Loaded: %s' % str(self)) |
| 462 | 461 |
| 463 # Arguments number differs from overridden method | 462 # Arguments number differs from overridden method |
| 464 # pylint: disable=W0221 | 463 # pylint: disable=W0221 |
| 465 def run(self, revision_overrides, command, args, work_queue, options): | 464 def run(self, revision_overrides, command, args, work_queue, options): |
| 466 """Runs 'command' before parsing the DEPS in case it's a initial checkout | 465 """Runs 'command' before parsing the DEPS in case it's a initial checkout |
| 467 or a revert.""" | 466 or a revert.""" |
| 468 | 467 |
| 469 def maybeGetParentRevision(options): | 468 def maybeGetParentRevision(options): |
| 470 """If we are performing an update and --transitive is set, set the | 469 """If we are performing an update and --transitive is set, set the |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 631 | 630 |
| 632 @property | 631 @property |
| 633 def recursion_limit(self): | 632 def recursion_limit(self): |
| 634 """Returns > 0 if this dependency is not too recursed to be processed. | 633 """Returns > 0 if this dependency is not too recursed to be processed. |
| 635 | 634 |
| 636 Immutable so no need to lock. | 635 Immutable so no need to lock. |
| 637 """ | 636 """ |
| 638 return max(self.parent.recursion_limit - 1, 0) | 637 return max(self.parent.recursion_limit - 1, 0) |
| 639 | 638 |
| 640 @property | 639 @property |
| 641 @gclient_utils.lockedmethod | 640 def dependencies(self): |
| 641 return tuple(self._dependencies) |
| 642 |
| 643 @property |
| 642 def file_list(self): | 644 def file_list(self): |
| 643 result = self._file_list[:] | 645 result = self._file_list[:] |
| 644 for d in self.dependencies: | 646 for d in self.dependencies: |
| 645 result.extend(d.file_list) | 647 result.extend(d.file_list) |
| 646 return tuple(result) | 648 return tuple(result) |
| 647 | 649 |
| 648 def __str__(self): | 650 def __str__(self): |
| 649 out = [] | 651 out = [] |
| 650 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', | 652 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', |
| 651 'custom_vars', 'deps_hooks', 'file_list', 'should_process', | 653 'custom_vars', 'deps_hooks', 'file_list', 'should_process', |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 try: | 756 try: |
| 755 exec(content, config_dict) | 757 exec(content, config_dict) |
| 756 except SyntaxError, e: | 758 except SyntaxError, e: |
| 757 gclient_utils.SyntaxErrorToError('.gclient', e) | 759 gclient_utils.SyntaxErrorToError('.gclient', e) |
| 758 for s in config_dict.get('solutions', []): | 760 for s in config_dict.get('solutions', []): |
| 759 try: | 761 try: |
| 760 tree = dict((d.name, d) for d in self.root.subtree(False)) | 762 tree = dict((d.name, d) for d in self.root.subtree(False)) |
| 761 if s['name'] in tree: | 763 if s['name'] in tree: |
| 762 raise gclient_utils.Error( | 764 raise gclient_utils.Error( |
| 763 'Dependency %s specified more than once in .gclient' % s['name']) | 765 'Dependency %s specified more than once in .gclient' % s['name']) |
| 764 self.dependencies.append(Dependency( | 766 self._dependencies.append(Dependency( |
| 765 self, s['name'], s['url'], | 767 self, s['name'], s['url'], |
| 766 s.get('safesync_url', None), | 768 s.get('safesync_url', None), |
| 767 s.get('managed', True), | 769 s.get('managed', True), |
| 768 s.get('custom_deps', {}), | 770 s.get('custom_deps', {}), |
| 769 s.get('custom_vars', {}), | 771 s.get('custom_vars', {}), |
| 770 s.get('deps_file', 'DEPS'), | 772 s.get('deps_file', 'DEPS'), |
| 771 True)) | 773 True)) |
| 772 except KeyError: | 774 except KeyError: |
| 773 raise gclient_utils.Error('Invalid .gclient file. Solution is ' | 775 raise gclient_utils.Error('Invalid .gclient file. Solution is ' |
| 774 'incomplete: %s' % s) | 776 'incomplete: %s' % s) |
| (...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1437 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1439 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 1438 print >> sys.stderr, 'Error: %s' % str(e) | 1440 print >> sys.stderr, 'Error: %s' % str(e) |
| 1439 return 1 | 1441 return 1 |
| 1440 | 1442 |
| 1441 | 1443 |
| 1442 if '__main__' == __name__: | 1444 if '__main__' == __name__: |
| 1443 fix_encoding.fix_encoding() | 1445 fix_encoding.fix_encoding() |
| 1444 sys.exit(Main(sys.argv[1:])) | 1446 sys.exit(Main(sys.argv[1:])) |
| 1445 | 1447 |
| 1446 # vim: ts=2:sw=2:tw=80:et: | 1448 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |