Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Side by Side Diff: gclient_scm.py

Issue 19359002: Allow gclient clone in non-empty directories (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: fixed another round of nits Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/gclient_scm_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 import re 11 import re
12 import sys 12 import sys
13 import tempfile
13 import threading 14 import threading
14 import time 15 import time
15 16
16 import gclient_utils 17 import gclient_utils
17 import scm 18 import scm
18 import subprocess2 19 import subprocess2
19 20
20 21
21 THIS_FILE_PATH = os.path.abspath(__file__) 22 THIS_FILE_PATH = os.path.abspath(__file__)
22 23
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 if revision.startswith('refs/'): 344 if revision.startswith('refs/'):
344 rev_type = "branch" 345 rev_type = "branch"
345 elif revision.startswith('origin/'): 346 elif revision.startswith('origin/'):
346 # For compatability with old naming, translate 'origin' to 'refs/heads' 347 # For compatability with old naming, translate 'origin' to 'refs/heads'
347 revision = revision.replace('origin/', 'refs/heads/') 348 revision = revision.replace('origin/', 'refs/heads/')
348 rev_type = "branch" 349 rev_type = "branch"
349 else: 350 else:
350 # hash is also a tag, only make a distinction at checkout 351 # hash is also a tag, only make a distinction at checkout
351 rev_type = "hash" 352 rev_type = "hash"
352 353
353 if not os.path.exists(self.checkout_path) or ( 354 if (not os.path.exists(self.checkout_path) or
354 os.path.isdir(self.checkout_path) and 355 (os.path.isdir(self.checkout_path) and
355 not os.listdir(self.checkout_path)): 356 not os.path.exists(os.path.join(self.checkout_path, '.git')))):
356 gclient_utils.safe_makedirs(os.path.dirname(self.checkout_path))
357 self._Clone(revision, url, options) 357 self._Clone(revision, url, options)
358 self.UpdateSubmoduleConfig() 358 self.UpdateSubmoduleConfig()
359 if file_list is not None: 359 if file_list is not None:
360 files = self._Capture(['ls-files']).splitlines() 360 files = self._Capture(['ls-files']).splitlines()
361 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) 361 file_list.extend([os.path.join(self.checkout_path, f) for f in files])
362 if not verbose: 362 if not verbose:
363 # Make the output a little prettier. It's nice to have some whitespace 363 # Make the output a little prettier. It's nice to have some whitespace
364 # between projects when cloning. 364 # between projects when cloning.
365 print('') 365 print('')
366 return 366 return
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 self._FetchAndReset(revision, file_list, options) 401 self._FetchAndReset(revision, file_list, options)
402 return_early = True 402 return_early = True
403 403
404 # Need to do this in the normal path as well as in the post-remote-switch 404 # Need to do this in the normal path as well as in the post-remote-switch
405 # path. 405 # path.
406 self._PossiblySwitchCache(url, options) 406 self._PossiblySwitchCache(url, options)
407 407
408 if return_early: 408 if return_early:
409 return 409 return
410 410
411 if not self._IsValidGitRepo():
412 # .git directory is hosed for some reason, set it back up.
413 print('_____ %s/.git is corrupted, rebuilding' % self.relpath)
414 self._Run(['init'], options)
415 self._Run(['remote', 'set-url', 'origin', url], options)
416
417 if not self._HasHead():
418 # Previous checkout was aborted before branches could be created in repo,
419 # so we need to reconstruct them here.
420 self._Run(['-c', 'core.deltaBaseCacheLimit=2g', 'pull', 'origin',
421 'master'], options)
422 self._FetchAndReset(revision, file_list, options)
423
424 cur_branch = self._GetCurrentBranch() 411 cur_branch = self._GetCurrentBranch()
425 412
426 # Cases: 413 # Cases:
427 # 0) HEAD is detached. Probably from our initial clone. 414 # 0) HEAD is detached. Probably from our initial clone.
428 # - make sure HEAD is contained by a named ref, then update. 415 # - make sure HEAD is contained by a named ref, then update.
429 # Cases 1-4. HEAD is a branch. 416 # Cases 1-4. HEAD is a branch.
430 # 1) current branch is not tracking a remote branch (could be git-svn) 417 # 1) current branch is not tracking a remote branch (could be git-svn)
431 # - try to rebase onto the new hash or branch 418 # - try to rebase onto the new hash or branch
432 # 2) current branch is tracking a remote branch with local committed 419 # 2) current branch is tracking a remote branch with local committed
433 # changes, but the DEPS file switched to point to a hash 420 # changes, but the DEPS file switched to point to a hash
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 revision is a branch head. If it is a tag or a specific commit, then we 839 revision is a branch head. If it is a tag or a specific commit, then we
853 leave HEAD detached as it makes future updates simpler -- in this case the 840 leave HEAD detached as it makes future updates simpler -- in this case the
854 user should first create a new branch or switch to an existing branch before 841 user should first create a new branch or switch to an existing branch before
855 making changes in the repo.""" 842 making changes in the repo."""
856 if not options.verbose: 843 if not options.verbose:
857 # git clone doesn't seem to insert a newline properly before printing 844 # git clone doesn't seem to insert a newline properly before printing
858 # to stdout 845 # to stdout
859 print('') 846 print('')
860 template_path = os.path.join( 847 template_path = os.path.join(
861 os.path.dirname(THIS_FILE_PATH), 'git-templates') 848 os.path.dirname(THIS_FILE_PATH), 'git-templates')
862 clone_cmd = ['-c', 'core.deltaBaseCacheLimit=2g', 'clone', '--progress', 849 clone_cmd = ['-c', 'core.deltaBaseCacheLimit=2g', 'clone', '--no-checkout',
863 '--template=%s' % template_path] 850 '--progress', '--template=%s' % template_path]
864 if self.cache_dir: 851 if self.cache_dir:
865 clone_cmd.append('--shared') 852 clone_cmd.append('--shared')
866 if revision.startswith('refs/heads/'):
867 clone_cmd.extend(['-b', revision.replace('refs/heads/', '')])
868 detach_head = False
869 else:
870 detach_head = True
871 if options.verbose: 853 if options.verbose:
872 clone_cmd.append('--verbose') 854 clone_cmd.append('--verbose')
873 clone_cmd.extend([url, self.checkout_path]) 855 clone_cmd.append(url)
874
875 # If the parent directory does not exist, Git clone on Windows will not 856 # If the parent directory does not exist, Git clone on Windows will not
876 # create it, so we need to do it manually. 857 # create it, so we need to do it manually.
877 parent_dir = os.path.dirname(self.checkout_path) 858 parent_dir = os.path.dirname(self.checkout_path)
878 if not os.path.exists(parent_dir): 859 gclient_utils.safe_makedirs(parent_dir)
879 gclient_utils.safe_makedirs(parent_dir) 860 tmp_dir = tempfile.mkdtemp(
880 861 prefix='_gclient_%s_' % os.path.basename(self.checkout_path),
881 for _ in range(3): 862 dir=parent_dir)
882 try: 863 try:
883 self._Run(clone_cmd, options, cwd=self._root_dir, git_filter=True) 864 clone_cmd.append(tmp_dir)
884 break 865 for i in xrange(3):
885 except subprocess2.CalledProcessError, e: 866 try:
886 # Too bad we don't have access to the actual output yet. 867 self._Run(clone_cmd, options, cwd=self._root_dir, git_filter=True)
887 # We should check for "transfer closed with NNN bytes remaining to 868 break
888 # read". In the meantime, just make sure .git exists. 869 except subprocess2.CalledProcessError as e:
889 if (e.returncode == 128 and 870 gclient_utils.rmtree(os.path.join(tmp_dir, '.git'))
890 os.path.exists(os.path.join(self.checkout_path, '.git'))): 871 if e.returncode != 128 or i == 2:
872 raise
891 print(str(e)) 873 print(str(e))
892 print('Retrying...') 874 print('Retrying...')
893 continue 875 gclient_utils.safe_makedirs(self.checkout_path)
894 raise e 876 os.rename(os.path.join(tmp_dir, '.git'),
895 877 os.path.join(self.checkout_path, '.git'))
896 # Update the "branch-heads" remote-tracking branches, since we might need it 878 finally:
897 # to checkout a specific revision below. 879 if os.listdir(tmp_dir):
898 self._UpdateBranchHeads(options, fetch=True) 880 print('\n_____ removing non-empty tmp dir %s' % tmp_dir)
899 881 gclient_utils.rmtree(tmp_dir)
900 if detach_head: 882 if revision.startswith('refs/heads/'):
883 self._Run(
884 ['checkout', '--quiet', revision.replace('refs/heads/', '')], options)
885 else:
901 # Squelch git's very verbose detached HEAD warning and use our own 886 # Squelch git's very verbose detached HEAD warning and use our own
902 self._Capture(['checkout', '--quiet', '%s' % revision]) 887 self._Run(['checkout', '--quiet', revision], options)
903 print( 888 print(
904 ('Checked out %s to a detached HEAD. Before making any commits\n' 889 ('Checked out %s to a detached HEAD. Before making any commits\n'
905 'in this repo, you should use \'git checkout <branch>\' to switch to\n' 890 'in this repo, you should use \'git checkout <branch>\' to switch to\n'
906 'an existing branch or use \'git checkout origin -b <branch>\' to\n' 891 'an existing branch or use \'git checkout origin -b <branch>\' to\n'
907 'create a new branch for your work.') % revision) 892 'create a new branch for your work.') % revision)
908 893
909 def _AttemptRebase(self, upstream, files, options, newbase=None, 894 def _AttemptRebase(self, upstream, files, options, newbase=None,
910 branch=None, printed_path=False): 895 branch=None, printed_path=False):
911 """Attempt to rebase onto either upstream or, if specified, newbase.""" 896 """Attempt to rebase onto either upstream or, if specified, newbase."""
912 if files is not None: 897 if files is not None:
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 "manually.\ncd %s && git " % 955 "manually.\ncd %s && git " %
971 self.checkout_path 956 self.checkout_path
972 + "%s" % ' '.join(rebase_cmd)) 957 + "%s" % ' '.join(rebase_cmd))
973 958
974 print(rebase_output.strip()) 959 print(rebase_output.strip())
975 if not options.verbose: 960 if not options.verbose:
976 # Make the output a little prettier. It's nice to have some 961 # Make the output a little prettier. It's nice to have some
977 # whitespace between projects when syncing. 962 # whitespace between projects when syncing.
978 print('') 963 print('')
979 964
980 def _IsValidGitRepo(self):
981 """Returns if the directory is a valid git repository.
982
983 Checks if git status works.
984 """
985 try:
986 self._Capture(['status'])
987 return True
988 except subprocess2.CalledProcessError:
989 return False
990
991 def _HasHead(self):
992 """Returns True if any commit is checked out.
993
994 This is done by checking if rev-parse HEAD works in the current repository.
995 """
996 try:
997 self._GetCurrentBranch()
998 return True
999 except subprocess2.CalledProcessError:
1000 return False
1001
1002 @staticmethod 965 @staticmethod
1003 def _CheckMinVersion(min_version): 966 def _CheckMinVersion(min_version):
1004 (ok, current_version) = scm.GIT.AssertVersion(min_version) 967 (ok, current_version) = scm.GIT.AssertVersion(min_version)
1005 if not ok: 968 if not ok:
1006 raise gclient_utils.Error('git version %s < minimum required %s' % 969 raise gclient_utils.Error('git version %s < minimum required %s' %
1007 (current_version, min_version)) 970 (current_version, min_version))
1008 971
1009 def _IsRebasing(self): 972 def _IsRebasing(self):
1010 # Check for any of REBASE-i/REBASE-m/REBASE/AM. Unfortunately git doesn't 973 # Check for any of REBASE-i/REBASE-m/REBASE/AM. Unfortunately git doesn't
1011 # have a plumbing command to determine whether a rebase is in progress, so 974 # have a plumbing command to determine whether a rebase is in progress, so
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after
1506 new_command.append('--force') 1469 new_command.append('--force')
1507 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1470 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1508 new_command.extend(('--accept', 'theirs-conflict')) 1471 new_command.extend(('--accept', 'theirs-conflict'))
1509 elif options.manually_grab_svn_rev: 1472 elif options.manually_grab_svn_rev:
1510 new_command.append('--force') 1473 new_command.append('--force')
1511 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1474 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1512 new_command.extend(('--accept', 'postpone')) 1475 new_command.extend(('--accept', 'postpone'))
1513 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1476 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1514 new_command.extend(('--accept', 'postpone')) 1477 new_command.extend(('--accept', 'postpone'))
1515 return new_command 1478 return new_command
OLDNEW
« no previous file with comments | « no previous file | tests/gclient_scm_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698