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

Side by Side Diff: gclient_scm.py

Issue 18768004: When switching to/from a cache git dir, try to reuse as much data as possible. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: When writing to a file, make the file writable! 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 | no next file » | 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
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 raise gclient_utils.Error('\n____ %s%s\n' 375 raise gclient_utils.Error('\n____ %s%s\n'
376 '\tPath is not a git repo. No .git dir.\n' 376 '\tPath is not a git repo. No .git dir.\n'
377 '\tTo resolve:\n' 377 '\tTo resolve:\n'
378 '\t\trm -rf %s\n' 378 '\t\trm -rf %s\n'
379 '\tAnd run gclient sync again\n' 379 '\tAnd run gclient sync again\n'
380 % (self.relpath, rev_str, self.relpath)) 380 % (self.relpath, rev_str, self.relpath))
381 381
382 # See if the url has changed (the unittests use git://foo for the url, let 382 # See if the url has changed (the unittests use git://foo for the url, let
383 # that through). 383 # that through).
384 current_url = self._Capture(['config', 'remote.origin.url']) 384 current_url = self._Capture(['config', 'remote.origin.url'])
385 return_early = False
385 # TODO(maruel): Delete url != 'git://foo' since it's just to make the 386 # TODO(maruel): Delete url != 'git://foo' since it's just to make the
386 # unit test pass. (and update the comment above) 387 # unit test pass. (and update the comment above)
387 # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set. 388 # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set.
388 # This allows devs to use experimental repos which have a different url 389 # This allows devs to use experimental repos which have a different url
389 # but whose branch(s) are the same as official repos. 390 # but whose branch(s) are the same as official repos.
390 if (current_url != url and 391 if (current_url != url and
391 url != 'git://foo' and 392 url != 'git://foo' and
392 subprocess2.capture( 393 subprocess2.capture(
393 ['git', 'config', 'remote.origin.gclient-auto-fix-url'], 394 ['git', 'config', 'remote.origin.gclient-auto-fix-url'],
394 cwd=self.checkout_path).strip() != 'False'): 395 cwd=self.checkout_path).strip() != 'False'):
395 print('_____ switching %s to a new upstream' % self.relpath) 396 print('_____ switching %s to a new upstream' % self.relpath)
396 # Make sure it's clean 397 # Make sure it's clean
397 self._CheckClean(rev_str) 398 self._CheckClean(rev_str)
398 # Switch over to the new upstream 399 # Switch over to the new upstream
399 self._Run(['remote', 'set-url', 'origin', url], options) 400 self._Run(['remote', 'set-url', 'origin', url], options)
400 self._FetchAndReset(revision, file_list, options) 401 self._FetchAndReset(revision, file_list, options)
402 return_early = True
403
404 # Need to do this in the normal path as well as in the post-remote-switch
405 # path.
406 self._PossiblySwitchCache(url, options)
407
408 if return_early:
401 return 409 return
402 410
403 if not self._IsValidGitRepo(): 411 if not self._IsValidGitRepo():
404 # .git directory is hosed for some reason, set it back up. 412 # .git directory is hosed for some reason, set it back up.
405 print('_____ %s/.git is corrupted, rebuilding' % self.relpath) 413 print('_____ %s/.git is corrupted, rebuilding' % self.relpath)
406 self._Run(['init'], options) 414 self._Run(['init'], options)
407 self._Run(['remote', 'set-url', 'origin', url], options) 415 self._Run(['remote', 'set-url', 'origin', url], options)
408 416
409 if not self._HasHead(): 417 if not self._HasHead():
410 # Previous checkout was aborted before branches could be created in repo, 418 # Previous checkout was aborted before branches could be created in repo,
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 @staticmethod 736 @staticmethod
729 def _NormalizeGitURL(url): 737 def _NormalizeGitURL(url):
730 '''Takes a git url, strips the scheme, and ensures it ends with '.git'.''' 738 '''Takes a git url, strips the scheme, and ensures it ends with '.git'.'''
731 idx = url.find('://') 739 idx = url.find('://')
732 if idx != -1: 740 if idx != -1:
733 url = url[idx+3:] 741 url = url[idx+3:]
734 if not url.endswith('.git'): 742 if not url.endswith('.git'):
735 url += '.git' 743 url += '.git'
736 return url 744 return url
737 745
746 def _PossiblySwitchCache(self, url, options):
747 """Handles switching a repo from with-cache to direct, or vice versa.
748
749 When we go from direct to with-cache, the remote url changes from the
750 'real' url to the local file url (in cache_dir). Therefore, this function
751 assumes that |url| points to the correctly-switched-over local file url, if
752 we're in cache_mode.
753
754 When we go from with-cache to direct, assume that the normal url-switching
755 code already flipped the remote over, and we just need to repack and break
756 the dependency to the cache.
757 """
758
759 altfile = os.path.join(
760 self.checkout_path, '.git', 'objects', 'info', 'alternates')
761 if self.cache_dir:
762 if not os.path.exists(altfile):
763 try:
764 with open(altfile, 'wa') as f:
765 f.write(os.path.join(url, 'objects'))
766 # pylint: disable=C0301
767 # This dance is necessary according to emperical evidence, also at:
768 # http://lists-archives.com/git/713652-retrospectively-add-alternates- to-a-repository.html
769 self._Run(['repack', '-ad'], options)
770 self._Run(['repack', '-adl'], options)
771 except Exception:
772 # If something goes wrong, try to remove the altfile so we'll go down
773 # this path again next time.
774 try:
775 os.remove(altfile)
776 except Exception:
777 pass
778 raise
779 else:
780 if os.path.exists(altfile):
781 self._Run(['repack', '-a'], options)
782 os.remove(altfile)
783
738 def _CreateOrUpdateCache(self, url, options): 784 def _CreateOrUpdateCache(self, url, options):
739 """Make a new git mirror or update existing mirror for |url|, and return the 785 """Make a new git mirror or update existing mirror for |url|, and return the
740 mirror URI to clone from. 786 mirror URI to clone from.
741 787
742 If no cache-dir is specified, just return |url| unchanged. 788 If no cache-dir is specified, just return |url| unchanged.
743 """ 789 """
744 if not self.cache_dir: 790 if not self.cache_dir:
745 return url 791 return url
746 792
747 # Replace - with -- to avoid ambiguity. / with - to flatten folder structure 793 # Replace - with -- to avoid ambiguity. / with - to flatten folder structure
748 folder = os.path.join( 794 folder = os.path.join(
749 self.cache_dir, 795 self.cache_dir,
750 self._NormalizeGitURL(url).replace('-', '--').replace('/', '-')) 796 self._NormalizeGitURL(url).replace('-', '--').replace('/', '-'))
797 altfile = os.path.join(folder, 'objects', 'info', 'alternates')
798
799 # If we're bringing an old cache up to date or cloning a new cache, and the
800 # existing repo is currently a direct clone, use its objects to help out
801 # the fetch here.
802 checkout_objects = os.path.join(self.checkout_path, '.git', 'objects')
803 checkout_altfile = os.path.join(checkout_objects, 'info', 'alternates')
804 use_reference = (
805 os.path.exists(checkout_objects) and
806 not os.path.exists(checkout_altfile))
751 807
752 v = ['-v'] if options.verbose else [] 808 v = ['-v'] if options.verbose else []
753 filter_fn = lambda l: '[up to date]' not in l 809 filter_fn = lambda l: '[up to date]' not in l
754 with self.cache_locks[folder]: 810 with self.cache_locks[folder]:
755 gclient_utils.safe_makedirs(self.cache_dir) 811 gclient_utils.safe_makedirs(self.cache_dir)
756 if not os.path.exists(os.path.join(folder, 'config')): 812 if not os.path.exists(os.path.join(folder, 'config')):
757 gclient_utils.rmtree(folder) 813 gclient_utils.rmtree(folder)
758 self._Run(['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g', 814 cmd = ['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g',
759 '--progress', '--mirror', url, folder], 815 '--progress', '--mirror']
816
817 if use_reference:
818 cmd += ['--reference', os.path.abspath(self.checkout_path)]
819
820 self._Run(cmd + [url, folder],
760 options, git_filter=True, filter_fn=filter_fn, 821 options, git_filter=True, filter_fn=filter_fn,
761 cwd=self.cache_dir) 822 cwd=self.cache_dir)
762 else: 823 else:
763 # For now, assert that host/path/to/repo.git is identical. We may want 824 # For now, assert that host/path/to/repo.git is identical. We may want
764 # to relax this restriction in the future to allow for smarter cache 825 # to relax this restriction in the future to allow for smarter cache
765 # repo update schemes (such as pulling the same repo, but from a 826 # repo update schemes (such as pulling the same repo, but from a
766 # different host). 827 # different host).
767 existing_url = self._Capture(['config', 'remote.origin.url'], 828 existing_url = self._Capture(['config', 'remote.origin.url'],
768 cwd=folder) 829 cwd=folder)
769 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) 830 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url)
770 831
832 if use_reference:
833 with open(altfile, 'w') as f:
834 f.write(os.path.abspath(checkout_objects))
835
771 # Would normally use `git remote update`, but it doesn't support 836 # Would normally use `git remote update`, but it doesn't support
772 # --progress, so use fetch instead. 837 # --progress, so use fetch instead.
773 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], 838 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'],
774 options, git_filter=True, filter_fn=filter_fn, cwd=folder) 839 options, git_filter=True, filter_fn=filter_fn, cwd=folder)
840
841 # If the clone has an object dependency on the existing repo, break it
842 # with repack and remove the linkage.
843 if os.path.exists(altfile):
844 self._Run(['repack', '-a'], options, cwd=folder)
845 os.remove(altfile)
775 return folder 846 return folder
776 847
777 def _Clone(self, revision, url, options): 848 def _Clone(self, revision, url, options):
778 """Clone a git repository from the given URL. 849 """Clone a git repository from the given URL.
779 850
780 Once we've cloned the repo, we checkout a working branch if the specified 851 Once we've cloned the repo, we checkout a working branch if the specified
781 revision is a branch head. If it is a tag or a specific commit, then we 852 revision is a branch head. If it is a tag or a specific commit, then we
782 leave HEAD detached as it makes future updates simpler -- in this case the 853 leave HEAD detached as it makes future updates simpler -- in this case the
783 user should first create a new branch or switch to an existing branch before 854 user should first create a new branch or switch to an existing branch before
784 making changes in the repo.""" 855 making changes in the repo."""
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after
1435 new_command.append('--force') 1506 new_command.append('--force')
1436 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1507 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1437 new_command.extend(('--accept', 'theirs-conflict')) 1508 new_command.extend(('--accept', 'theirs-conflict'))
1438 elif options.manually_grab_svn_rev: 1509 elif options.manually_grab_svn_rev:
1439 new_command.append('--force') 1510 new_command.append('--force')
1440 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1511 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1441 new_command.extend(('--accept', 'postpone')) 1512 new_command.extend(('--accept', 'postpone'))
1442 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1513 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1443 new_command.extend(('--accept', 'postpone')) 1514 new_command.extend(('--accept', 'postpone'))
1444 return new_command 1515 return new_command
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698