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 | 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 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
291 # A cache of the files affected by the current operation, necessary for | 291 # A cache of the files affected by the current operation, necessary for |
292 # hooks. | 292 # hooks. |
293 self._file_list = [] | 293 self._file_list = [] |
294 # If it is not set to True, the dependency wasn't processed for its child | 294 # If it is not set to True, the dependency wasn't processed for its child |
295 # dependency, i.e. its DEPS wasn't read. | 295 # dependency, i.e. its DEPS wasn't read. |
296 self._deps_parsed = False | 296 self._deps_parsed = False |
297 # This dependency has been processed, i.e. checked out | 297 # This dependency has been processed, i.e. checked out |
298 self._processed = False | 298 self._processed = False |
299 # This dependency had its hook run | 299 # This dependency had its hook run |
300 self._hooks_ran = False | 300 self._hooks_ran = False |
301 # This is the scm used to checkout self.url. It may be used by dependencies | |
302 # to get the datetime of the revision we checked out. | |
303 self._used_scm = None | |
M-A Ruel
2013/04/12 15:28:17
I actually like the idea of keeping an initialized
| |
301 | 304 |
302 if not self.name and self.parent: | 305 if not self.name and self.parent: |
303 raise gclient_utils.Error('Dependency without name') | 306 raise gclient_utils.Error('Dependency without name') |
304 | 307 |
305 @property | 308 @property |
306 def requirements(self): | 309 def requirements(self): |
307 """Calculate the list of requirements.""" | 310 """Calculate the list of requirements.""" |
308 requirements = set() | 311 requirements = set() |
309 # self.parent is implicitly a requirement. This will be recursive by | 312 # self.parent is implicitly a requirement. This will be recursive by |
310 # definition. | 313 # definition. |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 self.add_dependencies_and_close(deps_to_add, local_scope.get('hooks', [])) | 534 self.add_dependencies_and_close(deps_to_add, local_scope.get('hooks', [])) |
532 logging.info('ParseDepsFile(%s) done' % self.name) | 535 logging.info('ParseDepsFile(%s) done' % self.name) |
533 | 536 |
534 def add_dependencies_and_close(self, deps_to_add, hooks): | 537 def add_dependencies_and_close(self, deps_to_add, hooks): |
535 """Adds the dependencies, hooks and mark the parsing as done.""" | 538 """Adds the dependencies, hooks and mark the parsing as done.""" |
536 for dep in deps_to_add: | 539 for dep in deps_to_add: |
537 if dep.verify_validity(): | 540 if dep.verify_validity(): |
538 self.add_dependency(dep) | 541 self.add_dependency(dep) |
539 self._mark_as_parsed(hooks) | 542 self._mark_as_parsed(hooks) |
540 | 543 |
541 @staticmethod | 544 def maybeGetParentRevision(self, |
M-A Ruel
2013/04/12 15:28:17
keep self on the next line.
kustermann
2013/04/15 08:59:13
Done.
| |
542 def maybeGetParentRevision( | |
543 command, options, parsed_url, parent_name, revision_overrides): | 545 command, options, parsed_url, parent_name, revision_overrides): |
544 """If we are performing an update and --transitive is set, set the | 546 """If we are performing an update and --transitive is set, set the |
M-A Ruel
2013/04/12 15:28:17
This sentence is hard to read. Try to capture what
kustermann
2013/04/15 08:59:13
I hope this is better.
| |
545 revision to the parent's revision. If we have an explicit revision | 547 revision to the parent's revision (if self.url is the same repo) or to the |
546 do nothing.""" | 548 timestamp of the parent revision (if parent is in a different repo). |
549 If we have an explicit revision do nothing.""" | |
547 if command == 'update' and options.transitive and not options.revision: | 550 if command == 'update' and options.transitive and not options.revision: |
548 _, revision = gclient_utils.SplitUrlRevision(parsed_url) | 551 _, revision = gclient_utils.SplitUrlRevision(parsed_url) |
549 if not revision: | 552 if not revision: |
550 options.revision = revision_overrides.get(parent_name) | 553 options.revision = revision_overrides.get(parent_name) |
551 if options.verbose and options.revision: | 554 if (options.revision and |
552 print("Using parent's revision date: %s" % options.revision) | 555 not gclient_utils.IsDateRevision(options.revision)): |
553 # If the parent has a revision override, then it must have been | 556 assert (self.parent != None and self.parent.used_scm != None) |
M-A Ruel
2013/04/12 15:28:17
No need for () and checks for None, just do:
asser
kustermann
2013/04/15 08:59:13
Done.
| |
554 # converted to date format. | 557 parent_revision_date = self.parent.used_scm.GetRevisionDate( |
555 assert (not options.revision or | 558 options.revision) |
556 gclient_utils.IsDateRevision(options.revision)) | 559 parent_revision = gclient_utils.MakeDateRevision(parent_revision_date) |
557 | 560 # If this dependency is in the same repository as parent it's url will |
558 @staticmethod | 561 # start with a slash. If so we take the parent revision instead of |
559 def maybeConvertToDateRevision( | 562 # it's timestamp. |
560 command, options, name, scm, revision_overrides): | 563 # (The timestamps of commits in google code are broken -- which can |
561 """If we are performing an update and --transitive is set, convert the | 564 # can result in dependencies to be checked out at the wrong revision) |
562 revision to a date-revision (if necessary). Instead of having | 565 if self.url.startswith('/'): |
563 -r 101 replace the revision with the time stamp of 101 (e.g. | 566 if options.verbose: |
564 "{2011-18-04}"). | 567 print("Not updating revision override from %s to %s. Using " |
M-A Ruel
2013/04/12 15:28:17
Use '' instead of "". (We are slowly replacing the
kustermann
2013/04/15 08:59:13
Done.
| |
565 This way dependencies are upgraded to the revision they had at the | 568 "parent's revision %s since we are in the same repository." |
566 check-in of revision 101.""" | 569 % (options.revision, parent_revision, options.revision)) |
567 if (command == 'update' and | 570 else: |
568 options.transitive and | 571 if options.verbose: |
569 options.revision and | 572 print("Updating revision override from %s to %s." % |
570 not gclient_utils.IsDateRevision(options.revision)): | 573 (options.revision, parent_revision)) |
571 revision_date = scm.GetRevisionDate(options.revision) | 574 revision_overrides[self.name] = parent_revision |
572 revision = gclient_utils.MakeDateRevision(revision_date) | 575 options.revision = parent_revision |
573 if options.verbose: | |
574 print("Updating revision override from %s to %s." % | |
575 (options.revision, revision)) | |
576 revision_overrides[name] = revision | |
577 | 576 |
578 # Arguments number differs from overridden method | 577 # Arguments number differs from overridden method |
579 # pylint: disable=W0221 | 578 # pylint: disable=W0221 |
580 def run(self, revision_overrides, command, args, work_queue, options): | 579 def run(self, revision_overrides, command, args, work_queue, options): |
581 """Runs |command| then parse the DEPS file.""" | 580 """Runs |command| then parse the DEPS file.""" |
582 logging.info('Dependency(%s).run()' % self.name) | 581 logging.info('Dependency(%s).run()' % self.name) |
583 assert self._file_list == [] | 582 assert self._file_list == [] |
584 if not self.should_process: | 583 if not self.should_process: |
585 return | 584 return |
586 # When running runhooks, there's no need to consult the SCM. | 585 # When running runhooks, there's no need to consult the SCM. |
587 # All known hooks are expected to run unconditionally regardless of working | 586 # All known hooks are expected to run unconditionally regardless of working |
588 # copy state, so skip the SCM status check. | 587 # copy state, so skip the SCM status check. |
589 run_scm = command not in ('runhooks', 'recurse', None) | 588 run_scm = command not in ('runhooks', 'recurse', None) |
590 parsed_url = self.LateOverride(self.url) | 589 parsed_url = self.LateOverride(self.url) |
591 file_list = [] | 590 file_list = [] |
592 if run_scm and parsed_url: | 591 if run_scm and parsed_url: |
593 if isinstance(parsed_url, self.FileImpl): | 592 if isinstance(parsed_url, self.FileImpl): |
594 # Special support for single-file checkout. | 593 # Special support for single-file checkout. |
595 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): | 594 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): |
596 # Sadly, pylint doesn't realize that parsed_url is of FileImpl. | 595 # Sadly, pylint doesn't realize that parsed_url is of FileImpl. |
597 # pylint: disable=E1103 | 596 # pylint: disable=E1103 |
598 options.revision = parsed_url.GetRevision() | 597 options.revision = parsed_url.GetRevision() |
599 scm = gclient_scm.SVNWrapper(parsed_url.GetPath(), | 598 self._used_scm = gclient_scm.SVNWrapper(parsed_url.GetPath(), |
M-A Ruel
2013/04/12 15:28:17
Example of why I dislike multi-line argument align
kustermann
2013/04/15 08:59:13
Done.
| |
600 self.root.root_dir, | 599 self.root.root_dir, |
601 self.name) | 600 self.name) |
602 scm.RunCommand('updatesingle', options, | 601 self._used_scm.RunCommand('updatesingle', options, |
603 args + [parsed_url.GetFilename()], | 602 args + [parsed_url.GetFilename()], |
604 file_list) | 603 file_list) |
605 else: | 604 else: |
606 # Create a shallow copy to mutate revision. | 605 # Create a shallow copy to mutate revision. |
607 options = copy.copy(options) | 606 options = copy.copy(options) |
608 options.revision = revision_overrides.get(self.name) | 607 options.revision = revision_overrides.get(self.name) |
609 self.maybeGetParentRevision( | 608 self.maybeGetParentRevision( |
610 command, options, parsed_url, self.parent.name, revision_overrides) | 609 command, options, parsed_url, self.parent.name, revision_overrides) |
611 scm = gclient_scm.CreateSCM(parsed_url, self.root.root_dir, self.name) | 610 self._used_scm = gclient_scm.CreateSCM( |
612 scm.RunCommand(command, options, args, file_list) | 611 parsed_url, self.root.root_dir, self.name) |
613 self.maybeConvertToDateRevision( | 612 self._used_scm.RunCommand(command, options, args, file_list) |
614 command, options, self.name, scm, revision_overrides) | |
615 file_list = [os.path.join(self.name, f.strip()) for f in file_list] | 613 file_list = [os.path.join(self.name, f.strip()) for f in file_list] |
616 | 614 |
617 # TODO(phajdan.jr): We should know exactly when the paths are absolute. | 615 # TODO(phajdan.jr): We should know exactly when the paths are absolute. |
618 # Convert all absolute paths to relative. | 616 # Convert all absolute paths to relative. |
619 for i in range(len(file_list)): | 617 for i in range(len(file_list)): |
620 # It depends on the command being executed (like runhooks vs sync). | 618 # It depends on the command being executed (like runhooks vs sync). |
621 if not os.path.isabs(file_list[i]): | 619 if not os.path.isabs(file_list[i]): |
622 continue | 620 continue |
623 prefix = os.path.commonprefix( | 621 prefix = os.path.commonprefix( |
624 [self.root.root_dir.lower(), file_list[i].lower()]) | 622 [self.root.root_dir.lower(), file_list[i].lower()]) |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
821 @gclient_utils.lockedmethod | 819 @gclient_utils.lockedmethod |
822 def hooks_ran(self): | 820 def hooks_ran(self): |
823 return self._hooks_ran | 821 return self._hooks_ran |
824 | 822 |
825 @property | 823 @property |
826 @gclient_utils.lockedmethod | 824 @gclient_utils.lockedmethod |
827 def file_list(self): | 825 def file_list(self): |
828 return tuple(self._file_list) | 826 return tuple(self._file_list) |
829 | 827 |
830 @property | 828 @property |
829 def used_scm(self): | |
M-A Ruel
2013/04/12 15:28:17
Add a docstring. It's actually poor that the other
kustermann
2013/04/15 08:59:13
Done.
| |
830 return self._used_scm | |
831 | |
832 @property | |
831 def file_list_and_children(self): | 833 def file_list_and_children(self): |
832 result = list(self.file_list) | 834 result = list(self.file_list) |
833 for d in self.dependencies: | 835 for d in self.dependencies: |
834 result.extend(d.file_list_and_children) | 836 result.extend(d.file_list_and_children) |
835 return tuple(result) | 837 return tuple(result) |
836 | 838 |
837 def __str__(self): | 839 def __str__(self): |
838 out = [] | 840 out = [] |
839 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', | 841 for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', |
840 'custom_vars', 'deps_hooks', 'file_list', 'should_process', | 842 'custom_vars', 'deps_hooks', 'file_list', 'should_process', |
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1775 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1777 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
1776 print >> sys.stderr, 'Error: %s' % str(e) | 1778 print >> sys.stderr, 'Error: %s' % str(e) |
1777 return 1 | 1779 return 1 |
1778 | 1780 |
1779 | 1781 |
1780 if '__main__' == __name__: | 1782 if '__main__' == __name__: |
1781 fix_encoding.fix_encoding() | 1783 fix_encoding.fix_encoding() |
1782 sys.exit(Main(sys.argv[1:])) | 1784 sys.exit(Main(sys.argv[1:])) |
1783 | 1785 |
1784 # vim: ts=2:sw=2:tw=80:et: | 1786 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |