OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Gclient-specific SCM-specific operations.""" | 5 """Gclient-specific SCM-specific operations.""" |
6 | 6 |
7 import collections | 7 import collections |
8 import logging | 8 import logging |
9 import os | 9 import os |
10 import posixpath | 10 import posixpath |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 command, self.__class__.__name__)) | 140 command, self.__class__.__name__)) |
141 | 141 |
142 return getattr(self, command)(options, args, file_list) | 142 return getattr(self, command)(options, args, file_list) |
143 | 143 |
144 | 144 |
145 class GitWrapper(SCMWrapper): | 145 class GitWrapper(SCMWrapper): |
146 """Wrapper for Git""" | 146 """Wrapper for Git""" |
147 name = 'git' | 147 name = 'git' |
148 remote = 'origin' | 148 remote = 'origin' |
149 | 149 |
150 cache_dir = None | 150 cache_dir = None |
agable
2014/02/28 02:06:32
...I don't see *any* code in this file that assign
Ryan Tseng
2014/02/28 02:22:50
Well 691 does, since it passes it into git cache p
agable
2014/02/28 02:38:24
No, 691 (thankfully) only uses self.cache_dir if i
| |
151 # If a given cache is used in a solution more than once, prevent multiple | 151 # If a given cache is used in a solution more than once, prevent multiple |
152 # threads from updating it simultaneously. | 152 # threads from updating it simultaneously. |
153 cache_locks = collections.defaultdict(threading.Lock) | 153 cache_locks = collections.defaultdict(threading.Lock) |
agable
2014/02/28 02:06:32
This can go away, I believe.
Ryan Tseng
2014/02/28 02:22:50
Done.
| |
154 | 154 |
155 def __init__(self, url=None, root_dir=None, relpath=None): | 155 def __init__(self, url=None, root_dir=None, relpath=None): |
156 """Removes 'git+' fake prefix from git URL.""" | 156 """Removes 'git+' fake prefix from git URL.""" |
157 if url.startswith('git+http://') or url.startswith('git+https://'): | 157 if url.startswith('git+http://') or url.startswith('git+https://'): |
158 url = url[4:] | 158 url = url[4:] |
159 SCMWrapper.__init__(self, url, root_dir, relpath) | 159 SCMWrapper.__init__(self, url, root_dir, relpath) |
160 | 160 |
161 @staticmethod | 161 @staticmethod |
162 def BinaryExists(): | 162 def BinaryExists(): |
163 """Returns true if the command exists.""" | 163 """Returns true if the command exists.""" |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
345 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], | 345 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], |
346 cwd=self.checkout_path).strip() != 'False'): | 346 cwd=self.checkout_path).strip() != 'False'): |
347 print('_____ switching %s to a new upstream' % self.relpath) | 347 print('_____ switching %s to a new upstream' % self.relpath) |
348 # Make sure it's clean | 348 # Make sure it's clean |
349 self._CheckClean(rev_str) | 349 self._CheckClean(rev_str) |
350 # Switch over to the new upstream | 350 # Switch over to the new upstream |
351 self._Run(['remote', 'set-url', self.remote, url], options) | 351 self._Run(['remote', 'set-url', self.remote, url], options) |
352 self._FetchAndReset(revision, file_list, options) | 352 self._FetchAndReset(revision, file_list, options) |
353 return_early = True | 353 return_early = True |
354 | 354 |
355 # Need to do this in the normal path as well as in the post-remote-switch | |
356 # path. | |
357 self._PossiblySwitchCache(url, options) | |
358 | |
359 if return_early: | 355 if return_early: |
360 return self._Capture(['rev-parse', '--verify', 'HEAD']) | 356 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
361 | 357 |
362 cur_branch = self._GetCurrentBranch() | 358 cur_branch = self._GetCurrentBranch() |
363 | 359 |
364 # Cases: | 360 # Cases: |
365 # 0) HEAD is detached. Probably from our initial clone. | 361 # 0) HEAD is detached. Probably from our initial clone. |
366 # - make sure HEAD is contained by a named ref, then update. | 362 # - make sure HEAD is contained by a named ref, then update. |
367 # Cases 1-4. HEAD is a branch. | 363 # Cases 1-4. HEAD is a branch. |
368 # 1) current branch is not tracking a remote branch (could be git-svn) | 364 # 1) current branch is not tracking a remote branch (could be git-svn) |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
674 '#Initial_checkout' ) % rev) | 670 '#Initial_checkout' ) % rev) |
675 | 671 |
676 return sha1 | 672 return sha1 |
677 | 673 |
678 def FullUrlForRelativeUrl(self, url): | 674 def FullUrlForRelativeUrl(self, url): |
679 # Strip from last '/' | 675 # Strip from last '/' |
680 # Equivalent to unix basename | 676 # Equivalent to unix basename |
681 base_url = self.url | 677 base_url = self.url |
682 return base_url[:base_url.rfind('/')] + url | 678 return base_url[:base_url.rfind('/')] + url |
683 | 679 |
684 @staticmethod | |
685 def _NormalizeGitURL(url): | |
686 '''Takes a git url, strips the scheme, and ensures it ends with '.git'.''' | |
687 idx = url.find('://') | |
688 if idx != -1: | |
689 url = url[idx+3:] | |
690 if not url.endswith('.git'): | |
691 url += '.git' | |
692 return url | |
693 | |
694 def _PossiblySwitchCache(self, url, options): | |
695 """Handles switching a repo from with-cache to direct, or vice versa. | |
696 | |
697 When we go from direct to with-cache, the remote url changes from the | |
698 'real' url to the local file url (in cache_dir). Therefore, this function | |
699 assumes that |url| points to the correctly-switched-over local file url, if | |
700 we're in cache_mode. | |
701 | |
702 When we go from with-cache to direct, assume that the normal url-switching | |
703 code already flipped the remote over, and we just need to repack and break | |
704 the dependency to the cache. | |
705 """ | |
706 | |
707 altfile = os.path.join( | |
708 self.checkout_path, '.git', 'objects', 'info', 'alternates') | |
709 if self.cache_dir: | |
710 if not os.path.exists(altfile): | |
711 try: | |
712 with open(altfile, 'w') as f: | |
713 f.write(os.path.join(url, 'objects')) | |
714 # pylint: disable=C0301 | |
715 # This dance is necessary according to emperical evidence, also at: | |
716 # http://lists-archives.com/git/713652-retrospectively-add-alternates- to-a-repository.html | |
717 self._Run(['repack', '-ad'], options) | |
718 self._Run(['repack', '-adl'], options) | |
719 except Exception: | |
720 # If something goes wrong, try to remove the altfile so we'll go down | |
721 # this path again next time. | |
722 try: | |
723 os.remove(altfile) | |
724 except OSError as e: | |
725 print >> sys.stderr, "FAILED: os.remove('%s') -> %s" % (altfile, e) | |
726 raise | |
727 else: | |
728 if os.path.exists(altfile): | |
729 self._Run(['repack', '-a'], options) | |
730 os.remove(altfile) | |
731 | |
732 def _CreateOrUpdateCache(self, url, options): | 680 def _CreateOrUpdateCache(self, url, options): |
733 """Make a new git mirror or update existing mirror for |url|, and return the | 681 """Make a new git mirror or update existing mirror for |url|, and return the |
734 mirror URI to clone from. | 682 mirror URI to clone from. |
735 | 683 |
736 If no cache-dir is specified, just return |url| unchanged. | 684 If no cache-dir is specified, just return |url| unchanged. |
737 """ | 685 """ |
738 if not self.cache_dir: | 686 if not self.cache_dir: |
739 return url | 687 return url |
740 | |
741 # Replace - with -- to avoid ambiguity. / with - to flatten folder structure | |
742 folder = os.path.join( | |
743 self.cache_dir, | |
744 self._NormalizeGitURL(url).replace('-', '--').replace('/', '-')) | |
745 altfile = os.path.join(folder, 'objects', 'info', 'alternates') | |
746 | |
747 # If we're bringing an old cache up to date or cloning a new cache, and the | |
748 # existing repo is currently a direct clone, use its objects to help out | |
749 # the fetch here. | |
750 checkout_objects = os.path.join(self.checkout_path, '.git', 'objects') | |
751 checkout_altfile = os.path.join(checkout_objects, 'info', 'alternates') | |
752 use_reference = ( | |
753 os.path.exists(checkout_objects) and | |
754 not os.path.exists(checkout_altfile)) | |
755 | |
756 v = ['-v'] if options.verbose else [] | 688 v = ['-v'] if options.verbose else [] |
757 filter_fn = lambda l: '[up to date]' not in l | 689 self._Run(['cache', 'populate'] + v + |
758 with self.cache_locks[folder]: | 690 ['--shallow', '--cache-dir', self.cache_dir, url], |
759 gclient_utils.safe_makedirs(self.cache_dir) | 691 options, cwd=self._root_dir, retry=True) |
760 if not os.path.exists(os.path.join(folder, 'config')): | 692 return self._Run(['cache', 'exists', '--cache-dir', self.cache_dir, url], |
761 gclient_utils.rmtree(folder) | 693 options).strip() |
762 cmd = ['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g', | |
763 '--progress', '--bare'] | |
764 | |
765 if use_reference: | |
766 cmd += ['--reference', os.path.abspath(self.checkout_path)] | |
767 | |
768 self._Run(cmd + [url, folder], | |
769 options, filter_fn=filter_fn, cwd=self.cache_dir, retry=True) | |
770 else: | |
771 # For now, assert that host/path/to/repo.git is identical. We may want | |
772 # to relax this restriction in the future to allow for smarter cache | |
773 # repo update schemes (such as pulling the same repo, but from a | |
774 # different host). | |
775 existing_url = self._Capture(['config', 'remote.%s.url' % self.remote], | |
776 cwd=folder) | |
777 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) | |
778 | |
779 if use_reference: | |
780 with open(altfile, 'w') as f: | |
781 f.write(os.path.abspath(checkout_objects)) | |
782 | |
783 # Would normally use `git remote update`, but it doesn't support | |
784 # --progress, so use fetch instead. | |
785 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], | |
786 options, filter_fn=filter_fn, cwd=folder, retry=True) | |
787 | |
788 # If the clone has an object dependency on the existing repo, break it | |
789 # with repack and remove the linkage. | |
790 if os.path.exists(altfile): | |
791 self._Run(['repack', '-a'], options, cwd=folder) | |
792 os.remove(altfile) | |
793 return folder | |
794 | 694 |
795 def _Clone(self, revision, url, options): | 695 def _Clone(self, revision, url, options): |
796 """Clone a git repository from the given URL. | 696 """Clone a git repository from the given URL. |
797 | 697 |
798 Once we've cloned the repo, we checkout a working branch if the specified | 698 Once we've cloned the repo, we checkout a working branch if the specified |
799 revision is a branch head. If it is a tag or a specific commit, then we | 699 revision is a branch head. If it is a tag or a specific commit, then we |
800 leave HEAD detached as it makes future updates simpler -- in this case the | 700 leave HEAD detached as it makes future updates simpler -- in this case the |
801 user should first create a new branch or switch to an existing branch before | 701 user should first create a new branch or switch to an existing branch before |
802 making changes in the repo.""" | 702 making changes in the repo.""" |
803 if not options.verbose: | 703 if not options.verbose: |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1037 # password prompt and simply allow git to fail noisily. The error | 937 # password prompt and simply allow git to fail noisily. The error |
1038 # message produced by git will be copied to gclient's output. | 938 # message produced by git will be copied to gclient's output. |
1039 env = kwargs.get('env') or kwargs.setdefault('env', os.environ.copy()) | 939 env = kwargs.get('env') or kwargs.setdefault('env', os.environ.copy()) |
1040 env.setdefault('GIT_ASKPASS', 'true') | 940 env.setdefault('GIT_ASKPASS', 'true') |
1041 env.setdefault('SSH_ASKPASS', 'true') | 941 env.setdefault('SSH_ASKPASS', 'true') |
1042 else: | 942 else: |
1043 kwargs.setdefault('print_stdout', True) | 943 kwargs.setdefault('print_stdout', True) |
1044 stdout = kwargs.get('stdout', sys.stdout) | 944 stdout = kwargs.get('stdout', sys.stdout) |
1045 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( | 945 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( |
1046 ' '.join(args), kwargs['cwd'])) | 946 ' '.join(args), kwargs['cwd'])) |
1047 gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs) | 947 return gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs) |
1048 | 948 |
1049 | 949 |
1050 class SVNWrapper(SCMWrapper): | 950 class SVNWrapper(SCMWrapper): |
1051 """ Wrapper for SVN """ | 951 """ Wrapper for SVN """ |
1052 name = 'svn' | 952 name = 'svn' |
1053 | 953 |
1054 @staticmethod | 954 @staticmethod |
1055 def BinaryExists(): | 955 def BinaryExists(): |
1056 """Returns true if the command exists.""" | 956 """Returns true if the command exists.""" |
1057 try: | 957 try: |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1506 new_command.append('--force') | 1406 new_command.append('--force') |
1507 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1407 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1508 new_command.extend(('--accept', 'theirs-conflict')) | 1408 new_command.extend(('--accept', 'theirs-conflict')) |
1509 elif options.manually_grab_svn_rev: | 1409 elif options.manually_grab_svn_rev: |
1510 new_command.append('--force') | 1410 new_command.append('--force') |
1511 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1411 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1512 new_command.extend(('--accept', 'postpone')) | 1412 new_command.extend(('--accept', 'postpone')) |
1513 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1413 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1514 new_command.extend(('--accept', 'postpone')) | 1414 new_command.extend(('--accept', 'postpone')) |
1515 return new_command | 1415 return new_command |
OLD | NEW |