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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 | 274 |
275 def _FetchAndReset(self, revision, file_list, options): | 275 def _FetchAndReset(self, revision, file_list, options): |
276 """Equivalent to git fetch; git reset.""" | 276 """Equivalent to git fetch; git reset.""" |
277 quiet = [] | 277 quiet = [] |
278 if not options.verbose: | 278 if not options.verbose: |
279 quiet = ['--quiet'] | 279 quiet = ['--quiet'] |
280 self._UpdateBranchHeads(options, fetch=False) | 280 self._UpdateBranchHeads(options, fetch=False) |
281 | 281 |
282 fetch_cmd = [ | 282 fetch_cmd = [ |
283 '-c', 'core.deltaBaseCacheLimit=2g', 'fetch', 'origin', '--prune'] | 283 '-c', 'core.deltaBaseCacheLimit=2g', 'fetch', 'origin', '--prune'] |
284 self._Run(fetch_cmd + quiet, options) | 284 self._Run(fetch_cmd + quiet, options, retry=True) |
285 self._Run(['reset', '--hard', revision] + quiet, options) | 285 self._Run(['reset', '--hard', revision] + quiet, options) |
286 self.UpdateSubmoduleConfig() | 286 self.UpdateSubmoduleConfig() |
287 if file_list is not None: | 287 if file_list is not None: |
288 files = self._Capture(['ls-files']).splitlines() | 288 files = self._Capture(['ls-files']).splitlines() |
289 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 289 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
290 | 290 |
291 def update(self, options, args, file_list): | 291 def update(self, options, args, file_list): |
292 """Runs git to update or transparently checkout the working copy. | 292 """Runs git to update or transparently checkout the working copy. |
293 | 293 |
294 All updated files will be appended to file_list. | 294 All updated files will be appended to file_list. |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 if not os.path.exists(os.path.join(folder, 'config')): | 795 if not os.path.exists(os.path.join(folder, 'config')): |
796 gclient_utils.rmtree(folder) | 796 gclient_utils.rmtree(folder) |
797 cmd = ['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g', | 797 cmd = ['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g', |
798 '--progress', '--mirror'] | 798 '--progress', '--mirror'] |
799 | 799 |
800 if use_reference: | 800 if use_reference: |
801 cmd += ['--reference', os.path.abspath(self.checkout_path)] | 801 cmd += ['--reference', os.path.abspath(self.checkout_path)] |
802 | 802 |
803 self._Run(cmd + [url, folder], | 803 self._Run(cmd + [url, folder], |
804 options, git_filter=True, filter_fn=filter_fn, | 804 options, git_filter=True, filter_fn=filter_fn, |
805 cwd=self.cache_dir) | 805 cwd=self.cache_dir, retry=True) |
806 else: | 806 else: |
807 # For now, assert that host/path/to/repo.git is identical. We may want | 807 # For now, assert that host/path/to/repo.git is identical. We may want |
808 # to relax this restriction in the future to allow for smarter cache | 808 # to relax this restriction in the future to allow for smarter cache |
809 # repo update schemes (such as pulling the same repo, but from a | 809 # repo update schemes (such as pulling the same repo, but from a |
810 # different host). | 810 # different host). |
811 existing_url = self._Capture(['config', 'remote.origin.url'], | 811 existing_url = self._Capture(['config', 'remote.origin.url'], |
812 cwd=folder) | 812 cwd=folder) |
813 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) | 813 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) |
814 | 814 |
815 if use_reference: | 815 if use_reference: |
816 with open(altfile, 'w') as f: | 816 with open(altfile, 'w') as f: |
817 f.write(os.path.abspath(checkout_objects)) | 817 f.write(os.path.abspath(checkout_objects)) |
818 | 818 |
819 # Would normally use `git remote update`, but it doesn't support | 819 # Would normally use `git remote update`, but it doesn't support |
820 # --progress, so use fetch instead. | 820 # --progress, so use fetch instead. |
821 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], | 821 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], |
822 options, git_filter=True, filter_fn=filter_fn, cwd=folder) | 822 options, git_filter=True, filter_fn=filter_fn, cwd=folder, |
| 823 retry=True) |
823 | 824 |
824 # If the clone has an object dependency on the existing repo, break it | 825 # If the clone has an object dependency on the existing repo, break it |
825 # with repack and remove the linkage. | 826 # with repack and remove the linkage. |
826 if os.path.exists(altfile): | 827 if os.path.exists(altfile): |
827 self._Run(['repack', '-a'], options, cwd=folder) | 828 self._Run(['repack', '-a'], options, cwd=folder) |
828 os.remove(altfile) | 829 os.remove(altfile) |
829 return folder | 830 return folder |
830 | 831 |
831 def _Clone(self, revision, url, options): | 832 def _Clone(self, revision, url, options): |
832 """Clone a git repository from the given URL. | 833 """Clone a git repository from the given URL. |
(...skipping 18 matching lines...) Expand all Loading... |
851 clone_cmd.append(url) | 852 clone_cmd.append(url) |
852 # If the parent directory does not exist, Git clone on Windows will not | 853 # If the parent directory does not exist, Git clone on Windows will not |
853 # create it, so we need to do it manually. | 854 # create it, so we need to do it manually. |
854 parent_dir = os.path.dirname(self.checkout_path) | 855 parent_dir = os.path.dirname(self.checkout_path) |
855 gclient_utils.safe_makedirs(parent_dir) | 856 gclient_utils.safe_makedirs(parent_dir) |
856 tmp_dir = tempfile.mkdtemp( | 857 tmp_dir = tempfile.mkdtemp( |
857 prefix='_gclient_%s_' % os.path.basename(self.checkout_path), | 858 prefix='_gclient_%s_' % os.path.basename(self.checkout_path), |
858 dir=parent_dir) | 859 dir=parent_dir) |
859 try: | 860 try: |
860 clone_cmd.append(tmp_dir) | 861 clone_cmd.append(tmp_dir) |
861 for i in xrange(3): | 862 self._Run(clone_cmd, options, cwd=self._root_dir, git_filter=True, |
862 try: | 863 retry=True) |
863 self._Run(clone_cmd, options, cwd=self._root_dir, git_filter=True) | |
864 break | |
865 except subprocess2.CalledProcessError as e: | |
866 gclient_utils.rmtree(os.path.join(tmp_dir, '.git')) | |
867 if e.returncode != 128 or i == 2: | |
868 raise | |
869 print(str(e)) | |
870 print('Retrying...') | |
871 gclient_utils.safe_makedirs(self.checkout_path) | 864 gclient_utils.safe_makedirs(self.checkout_path) |
872 gclient_utils.safe_rename(os.path.join(tmp_dir, '.git'), | 865 gclient_utils.safe_rename(os.path.join(tmp_dir, '.git'), |
873 os.path.join(self.checkout_path, '.git')) | 866 os.path.join(self.checkout_path, '.git')) |
874 finally: | 867 finally: |
875 if os.listdir(tmp_dir): | 868 if os.listdir(tmp_dir): |
876 print('\n_____ removing non-empty tmp dir %s' % tmp_dir) | 869 print('\n_____ removing non-empty tmp dir %s' % tmp_dir) |
877 gclient_utils.rmtree(tmp_dir) | 870 gclient_utils.rmtree(tmp_dir) |
878 if revision.startswith('refs/heads/'): | 871 if revision.startswith('refs/heads/'): |
879 self._Run( | 872 self._Run( |
880 ['checkout', '--quiet', revision.replace('refs/heads/', '')], options) | 873 ['checkout', '--quiet', revision.replace('refs/heads/', '')], options) |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 | 1020 |
1028 def _Capture(self, args, cwd=None): | 1021 def _Capture(self, args, cwd=None): |
1029 return subprocess2.check_output( | 1022 return subprocess2.check_output( |
1030 ['git'] + args, | 1023 ['git'] + args, |
1031 stderr=subprocess2.VOID, | 1024 stderr=subprocess2.VOID, |
1032 cwd=cwd or self.checkout_path).strip() | 1025 cwd=cwd or self.checkout_path).strip() |
1033 | 1026 |
1034 def _UpdateBranchHeads(self, options, fetch=False): | 1027 def _UpdateBranchHeads(self, options, fetch=False): |
1035 """Adds, and optionally fetches, "branch-heads" refspecs if requested.""" | 1028 """Adds, and optionally fetches, "branch-heads" refspecs if requested.""" |
1036 if hasattr(options, 'with_branch_heads') and options.with_branch_heads: | 1029 if hasattr(options, 'with_branch_heads') and options.with_branch_heads: |
1037 backoff_time = 5 | 1030 config_cmd = ['config', 'remote.origin.fetch', |
1038 for _ in range(3): | 1031 '+refs/branch-heads/*:refs/remotes/branch-heads/*', |
1039 try: | 1032 '^\\+refs/branch-heads/\\*:.*$'] |
1040 config_cmd = ['config', 'remote.origin.fetch', | 1033 self._Run(config_cmd, options) |
1041 '+refs/branch-heads/*:refs/remotes/branch-heads/*', | 1034 if fetch: |
1042 '^\\+refs/branch-heads/\\*:.*$'] | 1035 fetch_cmd = ['-c', 'core.deltaBaseCacheLimit=2g', 'fetch', 'origin'] |
1043 self._Run(config_cmd, options) | 1036 if options.verbose: |
1044 if fetch: | 1037 fetch_cmd.append('--verbose') |
1045 fetch_cmd = ['-c', 'core.deltaBaseCacheLimit=2g', 'fetch', 'origin'] | 1038 self._Run(fetch_cmd, options, retry=True) |
1046 if options.verbose: | |
1047 fetch_cmd.append('--verbose') | |
1048 self._Run(fetch_cmd, options) | |
1049 break | |
1050 except subprocess2.CalledProcessError, e: | |
1051 print(str(e)) | |
1052 print('Retrying in %.1f seconds...' % backoff_time) | |
1053 time.sleep(backoff_time) | |
1054 backoff_time *= 1.3 | |
1055 | 1039 |
1056 def _Run(self, args, _options, git_filter=False, **kwargs): | 1040 def _Run(self, args, _options, git_filter=False, **kwargs): |
1057 kwargs.setdefault('cwd', self.checkout_path) | 1041 kwargs.setdefault('cwd', self.checkout_path) |
1058 if git_filter: | 1042 if git_filter: |
1059 kwargs['filter_fn'] = GitFilter(kwargs.get('filter_fn')) | 1043 kwargs['filter_fn'] = GitFilter(kwargs.get('filter_fn')) |
1060 kwargs.setdefault('print_stdout', False) | 1044 kwargs.setdefault('print_stdout', False) |
1061 # Don't prompt for passwords; just fail quickly and noisily. | 1045 # Don't prompt for passwords; just fail quickly and noisily. |
1062 # By default, git will use an interactive terminal prompt when a username/ | 1046 # By default, git will use an interactive terminal prompt when a username/ |
1063 # password is needed. That shouldn't happen in the chromium workflow, | 1047 # password is needed. That shouldn't happen in the chromium workflow, |
1064 # and if it does, then gclient may hide the prompt in the midst of a flood | 1048 # and if it does, then gclient may hide the prompt in the midst of a flood |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1468 new_command.append('--force') | 1452 new_command.append('--force') |
1469 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1453 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1470 new_command.extend(('--accept', 'theirs-conflict')) | 1454 new_command.extend(('--accept', 'theirs-conflict')) |
1471 elif options.manually_grab_svn_rev: | 1455 elif options.manually_grab_svn_rev: |
1472 new_command.append('--force') | 1456 new_command.append('--force') |
1473 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1457 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1474 new_command.extend(('--accept', 'postpone')) | 1458 new_command.extend(('--accept', 'postpone')) |
1475 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1459 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1476 new_command.extend(('--accept', 'postpone')) | 1460 new_command.extend(('--accept', 'postpone')) |
1477 return new_command | 1461 return new_command |
OLD | NEW |