This commit is contained in:
Thierry Deo 2017-02-15 10:53:41 +01:00
parent 6cb92e067c
commit 3c4d673674
3 changed files with 34 additions and 73 deletions

View file

@ -11,7 +11,6 @@ import pkg_resources
from cached_property import cached_property from cached_property import cached_property
from pre_commit import five from pre_commit import five
from pre_commit.clientlib.validate_config import _LOCAL_HOOKS_MAGIC_REPO_STRING
from pre_commit.clientlib.validate_config import is_local_hooks from pre_commit.clientlib.validate_config import is_local_hooks
from pre_commit.clientlib.validate_manifest import MANIFEST_JSON_SCHEMA from pre_commit.clientlib.validate_manifest import MANIFEST_JSON_SCHEMA
from pre_commit.jsonschema_extensions import apply_defaults from pre_commit.jsonschema_extensions import apply_defaults
@ -41,9 +40,7 @@ class Repository(object):
def create(cls, config, store, owner): def create(cls, config, store, owner):
repo_path_getter = store.get_repo_path_getter( repo_path_getter = store.get_repo_path_getter(
config['repo'], config['repo'],
_LOCAL_HOOKS_MAGIC_REPO_STRING if owner if is_local_hooks(config) else config['sha'],
is_local_hooks(config) else config['sha'],
owner,
) )
if is_local_hooks(config): if is_local_hooks(config):
return LocalRepository(config, repo_path_getter) return LocalRepository(config, repo_path_getter)

View file

@ -44,18 +44,7 @@ class Store(object):
@cached_property @cached_property
def repo_path(self): def repo_path(self):
return self._store.clone(self._repo, self._ref) return self._store.initialize_repo(self._repo, self._sha)
class LocalRepoPathGetter(RepoPathGetter):
def __init__(self, repo, sha, store, owner):
super(Store.LocalRepoPathGetter, self).__init__(
repo, sha, store,
)
self._owner = owner
@cached_property
def repo_path(self):
return self._store.initialize_local_repo(self._owner)
def __init__(self, directory=None): def __init__(self, directory=None):
if directory is None: if directory is None:
@ -109,69 +98,44 @@ class Store(object):
self._create() self._create()
self.__created = True self.__created = True
def find_local_path(self, repo, ref): def initialize_repo(self, repo, sha):
"""Initializes the repository by cloning a remote or preparing an
empty local folder for local hooks. If the repo if 'local',
the sha used is the path to git_root of this repo so that several
local hooks for different projects are separated."""
self.require_created()
# Check if we already exist
with sqlite3.connect(self.db_path) as db: with sqlite3.connect(self.db_path) as db:
result = db.execute( result = db.execute(
'SELECT path FROM repos WHERE repo = ? AND ref = ?', 'SELECT path FROM repos WHERE repo = ? AND ref = ?',
[repo, ref], [repo, sha],
).fetchone() ).fetchone()
if result: if result:
return result[0] return result[0]
def store_path(self, repo, ref, path): logger.info('Initializing environment for {}.'.format(repo))
dir = tempfile.mkdtemp(prefix='repo', dir=self.directory)
if repo != _LOCAL_HOOKS_MAGIC_REPO_STRING:
with clean_path_on_failure(dir):
cmd_output(
'git', 'clone', '--no-checkout', repo, dir,
env=no_git_env(),
)
with cwd(dir):
cmd_output('git', 'reset', sha, '--hard', env=no_git_env())
# Update our db with the created repo
with sqlite3.connect(self.db_path) as db: with sqlite3.connect(self.db_path) as db:
db.execute( db.execute(
'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)', 'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',
[repo, ref, path], [repo, sha, dir],
) )
def clone(self, url, sha):
"""Clone the given url and checkout the specific sha."""
self.require_created()
# Check if we already exist
local_path = self.find_local_path(url, sha)
if local_path:
return local_path
logger.info('Initializing environment for {}.'.format(url))
dir = tempfile.mkdtemp(prefix='repo', dir=self.directory)
with clean_path_on_failure(dir):
cmd_output(
'git', 'clone', '--no-checkout', url, dir, env=no_git_env(),
)
with cwd(dir):
cmd_output('git', 'reset', ref, '--hard', env=no_git_env())
# Update our db with the created repo
self.store_path(url, sha, dir)
return dir return dir
def initialize_local_repo(self, owner): def get_repo_path_getter(self, repo, sha):
"""Initializes a repo in the default repository for the local repo""" return self.RepoPathGetter(repo, sha, self)
self.require_created()
local_path = self.find_local_path(
_LOCAL_HOOKS_MAGIC_REPO_STRING, owner,
)
if local_path:
return local_path
logger.info('Initializing environment for {}.'.format(
_LOCAL_HOOKS_MAGIC_REPO_STRING,
))
dir = tempfile.mkdtemp(prefix='repo', dir=self.directory)
# Update our db with the created repo
self.store_path(_LOCAL_HOOKS_MAGIC_REPO_STRING, owner, dir)
return dir
def get_repo_path_getter(self, repo, sha, owner=None):
if sha == _LOCAL_HOOKS_MAGIC_REPO_STRING:
return self.LocalRepoPathGetter(repo, sha, self, owner)
else:
return self.RepoPathGetter(repo, sha, self)
@cached_property @cached_property
def cmd_runner(self): def cmd_runner(self):

View file

@ -79,14 +79,14 @@ def test_does_not_recreate_if_directory_already_exists(store):
assert not os.path.exists(os.path.join(store.directory, 'README')) assert not os.path.exists(os.path.join(store.directory, 'README'))
def test_clone(store, tempdir_factory, log_info_mock): def test_initialize_repo(store, tempdir_factory, log_info_mock):
path = git_dir(tempdir_factory) path = git_dir(tempdir_factory)
with cwd(path): with cwd(path):
cmd_output('git', 'commit', '--allow-empty', '-m', 'foo') cmd_output('git', 'commit', '--allow-empty', '-m', 'foo')
sha = get_head_sha(path) sha = get_head_sha(path)
cmd_output('git', 'commit', '--allow-empty', '-m', 'bar') cmd_output('git', 'commit', '--allow-empty', '-m', 'bar')
ret = store.clone(path, sha) ret = store.initialize_repo(path, sha)
# Should have printed some stuff # Should have printed some stuff
assert log_info_mock.call_args_list[0][0][0].startswith( assert log_info_mock.call_args_list[0][0][0].startswith(
'Initializing environment for ' 'Initializing environment for '
@ -98,7 +98,7 @@ def test_clone(store, tempdir_factory, log_info_mock):
# Directory should start with `repo` # Directory should start with `repo`
_, dirname = os.path.split(ret) _, dirname = os.path.split(ret)
assert dirname.startswith('repo') assert dirname.startswith('repo')
# Should be checked out to the sha we specified # Should be checked out to the sha we specifieds
assert get_head_sha(ret) == sha assert get_head_sha(ret) == sha
# Assert there's an entry in the sqlite db for this # Assert there's an entry in the sqlite db for this
@ -110,11 +110,11 @@ def test_clone(store, tempdir_factory, log_info_mock):
assert path == ret assert path == ret
def test_clone_cleans_up_on_checkout_failure(store): def test_initialize_repo_cleans_up_on_checkout_failure(store):
try: try:
# This raises an exception because you can't clone something that # This raises an exception because you can't clone something that
# doesn't exist! # doesn't exist!
store.clone('/i_dont_exist_lol', 'fake_sha') store.initialize_repo('/i_dont_exist_lol', 'fake_sha')
except Exception as e: except Exception as e:
assert '/i_dont_exist_lol' in five.text(e) assert '/i_dont_exist_lol' in five.text(e)
@ -130,7 +130,7 @@ def test_has_cmd_runner_at_directory(store):
assert ret.prefix_dir == store.directory + os.sep assert ret.prefix_dir == store.directory + os.sep
def test_clone_when_repo_already_exists(store): def test_initialize_repo_when_repo_already_exists(store):
# Create an entry in the sqlite db that makes it look like the repo has # Create an entry in the sqlite db that makes it look like the repo has
# been cloned. # been cloned.
store.require_created() store.require_created()
@ -141,7 +141,7 @@ def test_clone_when_repo_already_exists(store):
'VALUES ("fake_repo", "fake_ref", "fake_path")' 'VALUES ("fake_repo", "fake_ref", "fake_path")'
) )
assert store.clone('fake_repo', 'fake_ref') == 'fake_path' assert store.initialize_repo('fake_repo', 'fake_ref') == 'fake_path'
def test_require_created_when_directory_exists_but_not_db(store): def test_require_created_when_directory_exists_but_not_db(store):