| Index: git_cache.py
|
| diff --git a/git_cache.py b/git_cache.py
|
| index 75fb29ac4a638cc87353e04b957a53f383bc7dc9..ae8a5194878ac98f69bf0fcee1558fcec147837d 100755
|
| --- a/git_cache.py
|
| +++ b/git_cache.py
|
| @@ -13,6 +13,7 @@ import os
|
| import re
|
| import tempfile
|
| import time
|
| +import shutil
|
| import subprocess
|
| import sys
|
| import urlparse
|
| @@ -25,6 +26,8 @@ import subcommand
|
| # Analogous to gc.autopacklimit git config.
|
| GC_AUTOPACKLIMIT = 50
|
|
|
| +GIT_CACHE_CORRUPT_MESSAGE = 'WARNING: The Git cache is corrupt.'
|
| +
|
| try:
|
| # pylint: disable=E0602
|
| WinErr = WindowsError
|
| @@ -35,6 +38,8 @@ except NameError:
|
| class LockError(Exception):
|
| pass
|
|
|
| +class RefsHeadsFailedToFetch(Exception):
|
| + pass
|
|
|
| class Lockfile(object):
|
| """Class to represent a cross-platform process-specific lockfile."""
|
| @@ -248,7 +253,10 @@ class Mirror(object):
|
| self.RunGit(['config', '--add', 'remote.origin.fetch', refspec], cwd=cwd)
|
|
|
| def bootstrap_repo(self, directory):
|
| - """Bootstrap the repo from Google Stroage if possible."""
|
| + """Bootstrap the repo from Google Stroage if possible.
|
| +
|
| + More apt-ly named bootstrap_repo_from_cloud_if_possible_else_do_nothing().
|
| + """
|
|
|
| python_fallback = False
|
| if sys.platform.startswith('win') and not self.FindExecutable('7z'):
|
| @@ -309,75 +317,96 @@ class Mirror(object):
|
| def exists(self):
|
| return os.path.isfile(os.path.join(self.mirror_path, 'config'))
|
|
|
| - def populate(self, depth=None, shallow=False, bootstrap=False,
|
| - verbose=False, ignore_lock=False):
|
| - assert self.GetCachePath()
|
| - if shallow and not depth:
|
| - depth = 10000
|
| - gclient_utils.safe_makedirs(self.GetCachePath())
|
| + def _ensure_bootstrapped(self, depth, bootstrap, force=False):
|
| + tempdir = None
|
| + config_file = os.path.join(self.mirror_path, 'config')
|
| + pack_dir = os.path.join(self.mirror_path, 'objects', 'pack')
|
| + pack_files = []
|
| +
|
| + if os.path.isdir(pack_dir):
|
| + pack_files = [f for f in os.listdir(pack_dir) if f.endswith('.pack')]
|
| +
|
| + should_bootstrap = (force or
|
| + not os.path.exists(config_file) or
|
| + len(pack_files) > GC_AUTOPACKLIMIT)
|
| + if should_bootstrap:
|
| + tempdir = tempfile.mkdtemp(
|
| + prefix='_cache_tmp', suffix=self.basedir, dir=self.GetCachePath())
|
| + bootstrapped = not depth and bootstrap and self.bootstrap_repo(tempdir)
|
| + if bootstrapped:
|
| + # Bootstrap succeeded; delete previous cache, if any.
|
| + try:
|
| + # Try to move folder to tempdir if possible.
|
| + defunct_dir = tempfile.mkdtemp()
|
| + shutil.move(self.mirror_path, defunct_dir)
|
| + self.print('Moved defunct directory for repository %s from %s to %s'
|
| + % (self.url, self.mirror_path, defunct_dir))
|
| + except Exception:
|
| + gclient_utils.rmtree(self.mirror_path)
|
| + elif not os.path.exists(config_file):
|
| + # Bootstrap failed, no previous cache; start with a bare git dir.
|
| + self.RunGit(['init', '--bare'], cwd=tempdir)
|
| + else:
|
| + # Bootstrap failed, previous cache exists; warn and continue.
|
| + logging.warn(
|
| + 'Git cache has a lot of pack files (%d). Tried to re-bootstrap '
|
| + 'but failed. Continuing with non-optimized repository.'
|
| + % len(pack_files))
|
| + gclient_utils.rmtree(tempdir)
|
| + tempdir = None
|
| + else:
|
| + if depth and os.path.exists(os.path.join(self.mirror_path, 'shallow')):
|
| + logging.warn(
|
| + 'Shallow fetch requested, but repo cache already exists.')
|
| + return tempdir
|
|
|
| + def _fetch(self, rundir, verbose, depth):
|
| + self.config(rundir)
|
| v = []
|
| + d = []
|
| if verbose:
|
| v = ['-v', '--progress']
|
| -
|
| - d = []
|
| if depth:
|
| d = ['--depth', str(depth)]
|
| + fetch_cmd = ['fetch'] + v + d + ['origin']
|
| + fetch_specs = subprocess.check_output(
|
| + [self.git_exe, 'config', '--get-all', 'remote.origin.fetch'],
|
| + cwd=rundir).strip().splitlines()
|
| + for spec in fetch_specs:
|
| + try:
|
| + self.print('Fetching %s' % spec)
|
| + self.RunGit(fetch_cmd + [spec], cwd=rundir, retry=True)
|
| + except subprocess.CalledProcessError:
|
| + if spec == '+refs/heads/*:refs/heads/*':
|
| + raise RefsHeadsFailedToFetch
|
| + logging.warn('Fetch of %s failed' % spec)
|
|
|
| + def populate(self, depth=None, shallow=False, bootstrap=False,
|
| + verbose=False, ignore_lock=False):
|
| + assert self.GetCachePath()
|
| + if shallow and not depth:
|
| + depth = 10000
|
| + gclient_utils.safe_makedirs(self.GetCachePath())
|
|
|
| lockfile = Lockfile(self.mirror_path)
|
| if not ignore_lock:
|
| lockfile.lock()
|
|
|
| + tempdir = None
|
| try:
|
| - # Setup from scratch if the repo is new or is in a bad state.
|
| - tempdir = None
|
| - config_file = os.path.join(self.mirror_path, 'config')
|
| - pack_dir = os.path.join(self.mirror_path, 'objects', 'pack')
|
| - pack_files = []
|
| - if os.path.isdir(pack_dir):
|
| - pack_files = [f for f in os.listdir(pack_dir) if f.endswith('.pack')]
|
| -
|
| - should_bootstrap = (not os.path.exists(config_file) or
|
| - len(pack_files) > GC_AUTOPACKLIMIT)
|
| - if should_bootstrap:
|
| - tempdir = tempfile.mkdtemp(
|
| - prefix='_cache_tmp', suffix=self.basedir, dir=self.GetCachePath())
|
| - bootstrapped = not depth and bootstrap and self.bootstrap_repo(tempdir)
|
| - if bootstrapped:
|
| - # Bootstrap succeeded; delete previous cache, if any.
|
| - gclient_utils.rmtree(self.mirror_path)
|
| - elif not os.path.exists(config_file):
|
| - # Bootstrap failed, no previous cache; start with a bare git dir.
|
| - self.RunGit(['init', '--bare'], cwd=tempdir)
|
| - else:
|
| - # Bootstrap failed, previous cache exists; warn and continue.
|
| - logging.warn(
|
| - 'Git cache has a lot of pack files (%d). Tried to re-bootstrap '
|
| - 'but failed. Continuing with non-optimized repository.'
|
| - % len(pack_files))
|
| - gclient_utils.rmtree(tempdir)
|
| - tempdir = None
|
| - else:
|
| - if depth and os.path.exists(os.path.join(self.mirror_path, 'shallow')):
|
| - logging.warn(
|
| - 'Shallow fetch requested, but repo cache already exists.')
|
| - d = []
|
| -
|
| + tempdir = self._ensure_bootstrapped(depth, bootstrap)
|
| rundir = tempdir or self.mirror_path
|
| - self.config(rundir)
|
| - fetch_cmd = ['fetch'] + v + d + ['origin']
|
| - fetch_specs = subprocess.check_output(
|
| - [self.git_exe, 'config', '--get-all', 'remote.origin.fetch'],
|
| - cwd=rundir).strip().splitlines()
|
| - for spec in fetch_specs:
|
| - try:
|
| - self.RunGit(fetch_cmd + [spec], cwd=rundir, retry=True)
|
| - except subprocess.CalledProcessError:
|
| - logging.warn('Fetch of %s failed' % spec)
|
| + self._fetch(rundir, verbose, depth)
|
| + except RefsHeadsFailedToFetch:
|
| + # This is a major failure, we need to clean and force a bootstrap.
|
| + gclient_utils.rmtree(rundir)
|
| + self.print(GIT_CACHE_CORRUPT_MESSAGE)
|
| + tempdir = self._ensure_bootstrapped(depth, bootstrap, force=True)
|
| + assert tempdir
|
| + self._fetch(tempdir or self.mirror_path, verbose, depth)
|
| + finally:
|
| if tempdir:
|
| os.rename(tempdir, self.mirror_path)
|
| - finally:
|
| if not ignore_lock:
|
| lockfile.unlock()
|
|
|
|
|