| 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):
|
|
|