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

Side by Side Diff: gclient_scm.py

Issue 180243006: Make gclient_scm.py use cache_dir (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Remove cache_locks, also more membership tests. Created 6 years, 9 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
« no previous file with comments | « gclient.py ('k') | gclient_utils.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
8 import logging 7 import logging
9 import os 8 import os
10 import posixpath 9 import posixpath
11 import re 10 import re
12 import sys 11 import sys
13 import tempfile 12 import tempfile
14 import threading
15 import traceback 13 import traceback
16 import urlparse 14 import urlparse
17 15
18 import download_from_google_storage 16 import download_from_google_storage
19 import gclient_utils 17 import gclient_utils
20 import scm 18 import scm
21 import subprocess2 19 import subprocess2
22 20
23 21
24 THIS_FILE_PATH = os.path.abspath(__file__) 22 THIS_FILE_PATH = os.path.abspath(__file__)
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 139
142 return getattr(self, command)(options, args, file_list) 140 return getattr(self, command)(options, args, file_list)
143 141
144 142
145 class GitWrapper(SCMWrapper): 143 class GitWrapper(SCMWrapper):
146 """Wrapper for Git""" 144 """Wrapper for Git"""
147 name = 'git' 145 name = 'git'
148 remote = 'origin' 146 remote = 'origin'
149 147
150 cache_dir = None 148 cache_dir = None
151 # If a given cache is used in a solution more than once, prevent multiple
152 # threads from updating it simultaneously.
153 cache_locks = collections.defaultdict(threading.Lock)
154 149
155 def __init__(self, url=None, root_dir=None, relpath=None): 150 def __init__(self, url=None, root_dir=None, relpath=None):
156 """Removes 'git+' fake prefix from git URL.""" 151 """Removes 'git+' fake prefix from git URL."""
157 if url.startswith('git+http://') or url.startswith('git+https://'): 152 if url.startswith('git+http://') or url.startswith('git+https://'):
158 url = url[4:] 153 url = url[4:]
159 SCMWrapper.__init__(self, url, root_dir, relpath) 154 SCMWrapper.__init__(self, url, root_dir, relpath)
160 155
161 @staticmethod 156 @staticmethod
162 def BinaryExists(): 157 def BinaryExists():
163 """Returns true if the command exists.""" 158 """Returns true if the command exists."""
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], 340 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote],
346 cwd=self.checkout_path).strip() != 'False'): 341 cwd=self.checkout_path).strip() != 'False'):
347 print('_____ switching %s to a new upstream' % self.relpath) 342 print('_____ switching %s to a new upstream' % self.relpath)
348 # Make sure it's clean 343 # Make sure it's clean
349 self._CheckClean(rev_str) 344 self._CheckClean(rev_str)
350 # Switch over to the new upstream 345 # Switch over to the new upstream
351 self._Run(['remote', 'set-url', self.remote, url], options) 346 self._Run(['remote', 'set-url', self.remote, url], options)
352 self._FetchAndReset(revision, file_list, options) 347 self._FetchAndReset(revision, file_list, options)
353 return_early = True 348 return_early = True
354 349
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: 350 if return_early:
360 return self._Capture(['rev-parse', '--verify', 'HEAD']) 351 return self._Capture(['rev-parse', '--verify', 'HEAD'])
361 352
362 cur_branch = self._GetCurrentBranch() 353 cur_branch = self._GetCurrentBranch()
363 354
364 # Cases: 355 # Cases:
365 # 0) HEAD is detached. Probably from our initial clone. 356 # 0) HEAD is detached. Probably from our initial clone.
366 # - make sure HEAD is contained by a named ref, then update. 357 # - make sure HEAD is contained by a named ref, then update.
367 # Cases 1-4. HEAD is a branch. 358 # Cases 1-4. HEAD is a branch.
368 # 1) current branch is not tracking a remote branch (could be git-svn) 359 # 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
674 '#Initial_checkout' ) % rev) 665 '#Initial_checkout' ) % rev)
675 666
676 return sha1 667 return sha1
677 668
678 def FullUrlForRelativeUrl(self, url): 669 def FullUrlForRelativeUrl(self, url):
679 # Strip from last '/' 670 # Strip from last '/'
680 # Equivalent to unix basename 671 # Equivalent to unix basename
681 base_url = self.url 672 base_url = self.url
682 return base_url[:base_url.rfind('/')] + url 673 return base_url[:base_url.rfind('/')] + url
683 674
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): 675 def _CreateOrUpdateCache(self, url, options):
733 """Make a new git mirror or update existing mirror for |url|, and return the 676 """Make a new git mirror or update existing mirror for |url|, and return the
734 mirror URI to clone from. 677 mirror URI to clone from.
735 678
736 If no cache-dir is specified, just return |url| unchanged. 679 If no cache-dir is specified, just return |url| unchanged.
737 """ 680 """
738 if not self.cache_dir: 681 if not self.cache_dir:
739 return url 682 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 [] 683 v = ['-v'] if options.verbose else []
757 filter_fn = lambda l: '[up to date]' not in l 684 self._Run(['cache', 'populate'] + v +
758 with self.cache_locks[folder]: 685 ['--shallow', '--cache-dir', self.cache_dir, url],
759 gclient_utils.safe_makedirs(self.cache_dir) 686 options, cwd=self._root_dir, retry=True)
760 if not os.path.exists(os.path.join(folder, 'config')): 687 return self._Run(['cache', 'exists', '--cache-dir', self.cache_dir, url],
761 gclient_utils.rmtree(folder) 688 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 689
795 def _Clone(self, revision, url, options): 690 def _Clone(self, revision, url, options):
796 """Clone a git repository from the given URL. 691 """Clone a git repository from the given URL.
797 692
798 Once we've cloned the repo, we checkout a working branch if the specified 693 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 694 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 695 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 696 user should first create a new branch or switch to an existing branch before
802 making changes in the repo.""" 697 making changes in the repo."""
803 if not options.verbose: 698 if not options.verbose:
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
1037 # password prompt and simply allow git to fail noisily. The error 932 # password prompt and simply allow git to fail noisily. The error
1038 # message produced by git will be copied to gclient's output. 933 # message produced by git will be copied to gclient's output.
1039 env = kwargs.get('env') or kwargs.setdefault('env', os.environ.copy()) 934 env = kwargs.get('env') or kwargs.setdefault('env', os.environ.copy())
1040 env.setdefault('GIT_ASKPASS', 'true') 935 env.setdefault('GIT_ASKPASS', 'true')
1041 env.setdefault('SSH_ASKPASS', 'true') 936 env.setdefault('SSH_ASKPASS', 'true')
1042 else: 937 else:
1043 kwargs.setdefault('print_stdout', True) 938 kwargs.setdefault('print_stdout', True)
1044 stdout = kwargs.get('stdout', sys.stdout) 939 stdout = kwargs.get('stdout', sys.stdout)
1045 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( 940 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % (
1046 ' '.join(args), kwargs['cwd'])) 941 ' '.join(args), kwargs['cwd']))
1047 gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs) 942 return gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs)
1048 943
1049 944
1050 class SVNWrapper(SCMWrapper): 945 class SVNWrapper(SCMWrapper):
1051 """ Wrapper for SVN """ 946 """ Wrapper for SVN """
1052 name = 'svn' 947 name = 'svn'
1053 948
1054 @staticmethod 949 @staticmethod
1055 def BinaryExists(): 950 def BinaryExists():
1056 """Returns true if the command exists.""" 951 """Returns true if the command exists."""
1057 try: 952 try:
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after
1506 new_command.append('--force') 1401 new_command.append('--force')
1507 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1402 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1508 new_command.extend(('--accept', 'theirs-conflict')) 1403 new_command.extend(('--accept', 'theirs-conflict'))
1509 elif options.manually_grab_svn_rev: 1404 elif options.manually_grab_svn_rev:
1510 new_command.append('--force') 1405 new_command.append('--force')
1511 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1406 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1512 new_command.extend(('--accept', 'postpone')) 1407 new_command.extend(('--accept', 'postpone'))
1513 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1408 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1514 new_command.extend(('--accept', 'postpone')) 1409 new_command.extend(('--accept', 'postpone'))
1515 return new_command 1410 return new_command
OLDNEW
« no previous file with comments | « gclient.py ('k') | gclient_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698