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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gclient_scm.py
diff --git a/gclient_scm.py b/gclient_scm.py
index 5a5dc075b3c6c4b5ffb81b11c9702a37e1815dc2..fd7e3eed1c51fcdebefa3b64d08d7acd8f7c8ba8 100644
--- a/gclient_scm.py
+++ b/gclient_scm.py
@@ -382,6 +382,7 @@ class GitWrapper(SCMWrapper):
# See if the url has changed (the unittests use git://foo for the url, let
# that through).
current_url = self._Capture(['config', 'remote.origin.url'])
+ return_early = False
# TODO(maruel): Delete url != 'git://foo' since it's just to make the
# unit test pass. (and update the comment above)
# Skip url auto-correction if remote.origin.gclient-auto-fix-url is set.
@@ -398,6 +399,13 @@ class GitWrapper(SCMWrapper):
# Switch over to the new upstream
self._Run(['remote', 'set-url', 'origin', url], options)
self._FetchAndReset(revision, file_list, options)
+ return_early = True
+
+ # Need to do this in the normal path as well as in the post-remote-switch
+ # path.
+ self._PossiblySwitchCache(url, options)
+
+ if return_early:
return
if not self._IsValidGitRepo():
@@ -735,6 +743,44 @@ class GitWrapper(SCMWrapper):
url += '.git'
return url
+ def _PossiblySwitchCache(self, url, options):
+ """Handles switching a repo from with-cache to direct, or vice versa.
+
+ When we go from direct to with-cache, the remote url changes from the
+ 'real' url to the local file url (in cache_dir). Therefore, this function
+ assumes that |url| points to the correctly-switched-over local file url, if
+ we're in cache_mode.
+
+ When we go from with-cache to direct, assume that the normal url-switching
+ code already flipped the remote over, and we just need to repack and break
+ the dependency to the cache.
+ """
+
+ altfile = os.path.join(
+ self.checkout_path, '.git', 'objects', 'info', 'alternates')
+ if self.cache_dir:
+ if not os.path.exists(altfile):
+ try:
+ with open(altfile, 'wa') as f:
+ f.write(os.path.join(url, 'objects'))
+ # pylint: disable=C0301
+ # This dance is necessary according to emperical evidence, also at:
+ # http://lists-archives.com/git/713652-retrospectively-add-alternates-to-a-repository.html
+ self._Run(['repack', '-ad'], options)
+ self._Run(['repack', '-adl'], options)
+ except Exception:
+ # If something goes wrong, try to remove the altfile so we'll go down
+ # this path again next time.
+ try:
+ os.remove(altfile)
+ except Exception:
+ pass
+ raise
+ else:
+ if os.path.exists(altfile):
+ self._Run(['repack', '-a'], options)
+ os.remove(altfile)
+
def _CreateOrUpdateCache(self, url, options):
"""Make a new git mirror or update existing mirror for |url|, and return the
mirror URI to clone from.
@@ -748,6 +794,16 @@ class GitWrapper(SCMWrapper):
folder = os.path.join(
self.cache_dir,
self._NormalizeGitURL(url).replace('-', '--').replace('/', '-'))
+ altfile = os.path.join(folder, 'objects', 'info', 'alternates')
+
+ # If we're bringing an old cache up to date or cloning a new cache, and the
+ # existing repo is currently a direct clone, use its objects to help out
+ # the fetch here.
+ checkout_objects = os.path.join(self.checkout_path, '.git', 'objects')
+ checkout_altfile = os.path.join(checkout_objects, 'info', 'alternates')
+ use_reference = (
+ os.path.exists(checkout_objects) and
+ not os.path.exists(checkout_altfile))
v = ['-v'] if options.verbose else []
filter_fn = lambda l: '[up to date]' not in l
@@ -755,8 +811,13 @@ class GitWrapper(SCMWrapper):
gclient_utils.safe_makedirs(self.cache_dir)
if not os.path.exists(os.path.join(folder, 'config')):
gclient_utils.rmtree(folder)
- self._Run(['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g',
- '--progress', '--mirror', url, folder],
+ cmd = ['clone'] + v + ['-c', 'core.deltaBaseCacheLimit=2g',
+ '--progress', '--mirror']
+
+ if use_reference:
+ cmd += ['--reference', os.path.abspath(self.checkout_path)]
+
+ self._Run(cmd + [url, folder],
options, git_filter=True, filter_fn=filter_fn,
cwd=self.cache_dir)
else:
@@ -768,10 +829,20 @@ class GitWrapper(SCMWrapper):
cwd=folder)
assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url)
+ if use_reference:
+ with open(altfile, 'w') as f:
+ f.write(os.path.abspath(checkout_objects))
+
# Would normally use `git remote update`, but it doesn't support
# --progress, so use fetch instead.
self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'],
options, git_filter=True, filter_fn=filter_fn, cwd=folder)
+
+ # If the clone has an object dependency on the existing repo, break it
+ # with repack and remove the linkage.
+ if os.path.exists(altfile):
+ self._Run(['repack', '-a'], options, cwd=folder)
+ os.remove(altfile)
return folder
def _Clone(self, revision, url, options):
« 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