Implement `Store`. pre-commit now installs files to ~/.pre-commit · precommit/pre-commit@479eb51 · GitHub
Skip to content

Commit 479eb51

Browse files
committed
Implement Store. pre-commit now installs files to ~/.pre-commit
1 parent 26af2ce commit 479eb51

16 files changed

Lines changed: 457 additions & 234 deletions

.gitignore

Lines changed: 0 additions & 1 deletion

pre_commit/commands.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,17 @@ class RepositoryCannotBeUpdatedError(RuntimeError):
5656
pass
5757

5858

59-
def _update_repository(repo_config):
59+
def _update_repository(repo_config, runner):
6060
"""Updates a repository to the tip of `master`. If the repository cannot
6161
be updated because a hook that is configured does not exist in `master`,
6262
this raises a RepositoryCannotBeUpdatedError
6363
6464
Args:
6565
repo_config - A config for a repository
6666
"""
67-
repo = Repository(repo_config)
67+
repo = Repository.create(repo_config, runner.store)
6868

69-
with repo.in_checkout():
69+
with local.cwd(repo.repo_path_getter.repo_path):
7070
local['git']['fetch']()
7171
head_sha = local['git']['rev-parse', 'origin/master']().strip()
7272

@@ -77,11 +77,11 @@ def _update_repository(repo_config):
7777
# Construct a new config with the head sha
7878
new_config = OrderedDict(repo_config)
7979
new_config['sha'] = head_sha
80-
new_repo = Repository(new_config)
80+
new_repo = Repository.create(new_config, runner.store)
8181

8282
# See if any of our hooks were deleted with the new commits
8383
hooks = set(repo.hooks.keys())
84-
hooks_missing = hooks - (hooks & set(new_repo.manifest.keys()))
84+
hooks_missing = hooks - (hooks & set(new_repo.manifest.hooks.keys()))
8585
if hooks_missing:
8686
raise RepositoryCannotBeUpdatedError(
8787
'Cannot update because the tip of master is missing these hooks:\n'
@@ -106,7 +106,7 @@ def autoupdate(runner):
106106
sys.stdout.write('Updating {0}...'.format(repo_config['repo']))
107107
sys.stdout.flush()
108108
try:
109-
new_repo_config = _update_repository(repo_config)
109+
new_repo_config = _update_repository(repo_config, runner)
110110
except RepositoryCannotBeUpdatedError as error:
111111
print(error.args[0])
112112
output_configs.append(repo_config)
@@ -135,9 +135,9 @@ def autoupdate(runner):
135135

136136

137137
def clean(runner):
138-
if os.path.exists(runner.hooks_workspace_path):
139-
shutil.rmtree(runner.hooks_workspace_path)
140-
print('Cleaned {0}.'.format(runner.hooks_workspace_path))
138+
if os.path.exists(runner.store.directory):
139+
shutil.rmtree(runner.store.directory)
140+
print('Cleaned {0}.'.format(runner.store.directory))
141141
return 0
142142

143143

pre_commit/constants.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
CONFIG_FILE = '.pre-commit-config.yaml'
22

3-
HOOKS_WORKSPACE = '.pre-commit-files'
4-
53
MANIFEST_FILE = 'hooks.yaml'
64

75
YAML_DUMP_KWARGS = {

pre_commit/hooks_workspace.py

Lines changed: 0 additions & 20 deletions
This file was deleted.

pre_commit/manifest.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import os.path
2+
3+
import pre_commit.constants as C
4+
from pre_commit.clientlib.validate_manifest import load_manifest
5+
from pre_commit.util import cached_property
6+
7+
8+
class Manifest(object):
9+
def __init__(self, repo_path_getter):
10+
self.repo_path_getter = repo_path_getter
11+
12+
@cached_property
13+
def manifest_contents(self):
14+
manifest_path = os.path.join(
15+
self.repo_path_getter.repo_path, C.MANIFEST_FILE,
16+
)
17+
return load_manifest(manifest_path)
18+
19+
@cached_property
20+
def hooks(self):
21+
return dict((hook['id'], hook) for hook in self.manifest_contents)

pre_commit/repository.py

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
1-
import contextlib
2-
import logging
31
from asottile.ordereddict import OrderedDict
4-
from plumbum import local
52

6-
import pre_commit.constants as C
7-
from pre_commit import five
8-
from pre_commit.clientlib.validate_manifest import load_manifest
9-
from pre_commit.hooks_workspace import in_hooks_workspace
103
from pre_commit.languages.all import languages
4+
from pre_commit.manifest import Manifest
115
from pre_commit.prefixed_command_runner import PrefixedCommandRunner
126
from pre_commit.util import cached_property
13-
from pre_commit.util import clean_path_on_failure
14-
15-
16-
logger = logging.getLogger('pre_commit')
177

188

199
class Repository(object):
20-
def __init__(self, repo_config):
10+
def __init__(self, repo_config, repo_path_getter):
2111
self.repo_config = repo_config
22-
self.__created = False
12+
self.repo_path_getter = repo_path_getter
2313
self.__installed = False
2414

15+
@classmethod
16+
def create(cls, config, store):
17+
repo_path_getter = store.get_repo_path_getter(
18+
config['repo'], config['sha']
19+
)
20+
return cls(config, repo_path_getter)
21+
2522
@cached_property
2623
def repo_url(self):
2724
return self.repo_config['repo']
@@ -36,46 +33,22 @@ def languages(self):
3633

3734
@cached_property
3835
def hooks(self):
36+
# TODO: merging in manifest dicts is a smell imo
3937
return OrderedDict(
40-
(hook['id'], dict(hook, **self.manifest[hook['id']]))
38+
(hook['id'], dict(hook, **self.manifest.hooks[hook['id']]))
4139
for hook in self.repo_config['hooks']
4240
)
4341

4442
@cached_property
4543
def manifest(self):
46-
with self.in_checkout():
47-
return dict(
48-
(hook['id'], hook)
49-
for hook in load_manifest(C.MANIFEST_FILE)
50-
)
44+
return Manifest(self.repo_path_getter)
5145

5246
def get_cmd_runner(self, hooks_cmd_runner):
47+
# TODO: this effectively throws away the original cmd runner
5348
return PrefixedCommandRunner.from_command_runner(
54-
hooks_cmd_runner, self.sha,
49+
hooks_cmd_runner, self.repo_path_getter.repo_path,
5550
)
5651

57-
def require_created(self):
58-
if self.__created:
59-
return
60-
61-
self.create()
62-
self.__created = True
63-
64-
def create(self):
65-
with in_hooks_workspace():
66-
if local.path(self.sha).exists():
67-
# Project already exists, no reason to re-create it
68-
return
69-
70-
# Checking out environment for the first time
71-
logger.info('Installing environment for {0}.'.format(self.repo_url))
72-
logger.info('Once installed this environment will be reused.')
73-
logger.info('This may take a few minutes...')
74-
with clean_path_on_failure(five.u(local.path(self.sha))):
75-
local['git']['clone', '--no-checkout', self.repo_url, self.sha]()
76-
with self.in_checkout():
77-
local['git']['checkout', self.sha]()
78-
7952
def require_installed(self, cmd_runner):
8053
if self.__installed:
8154
return
@@ -89,7 +62,6 @@ def install(self, cmd_runner):
8962
Args:
9063
cmd_runner - A `PrefixedCommandRunner` bound to the hooks workspace
9164
"""
92-
self.require_created()
9365
repo_cmd_runner = self.get_cmd_runner(cmd_runner)
9466
for language_name in self.languages:
9567
language = languages[language_name]
@@ -101,13 +73,6 @@ def install(self, cmd_runner):
10173
continue
10274
language.install_environment(repo_cmd_runner)
10375

104-
@contextlib.contextmanager
105-
def in_checkout(self):
106-
self.require_created()
107-
with in_hooks_workspace():
108-
with local.cwd(self.sha):
109-
yield
110-
11176
def run_hook(self, cmd_runner, hook_id, file_args):
11277
"""Run a hook.
11378

pre_commit/runner.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import pre_commit.constants as C
55
from pre_commit import git
66
from pre_commit.clientlib.validate_config import load_config
7-
from pre_commit.prefixed_command_runner import PrefixedCommandRunner
87
from pre_commit.repository import Repository
8+
from pre_commit.store import Store
99
from pre_commit.util import cached_property
1010

1111

@@ -27,10 +27,6 @@ def create(cls):
2727
os.chdir(root)
2828
return cls(root)
2929

30-
@cached_property
31-
def hooks_workspace_path(self):
32-
return os.path.join(self.git_root, C.HOOKS_WORKSPACE)
33-
3430
@cached_property
3531
def config_file_path(self):
3632
return os.path.join(self.git_root, C.CONFIG_FILE)
@@ -39,12 +35,17 @@ def config_file_path(self):
3935
def repositories(self):
4036
"""Returns a tuple of the configured repositories."""
4137
config = load_config(self.config_file_path)
42-
return tuple(Repository(x) for x in config)
38+
return tuple(Repository.create(x, self.store) for x in config)
4339

4440
@cached_property
4541
def pre_commit_path(self):
4642
return os.path.join(self.git_root, '.git/hooks/pre-commit')
4743

4844
@cached_property
4945
def cmd_runner(self):
50-
return PrefixedCommandRunner(self.hooks_workspace_path)
46+
# TODO: remove this and inline runner.store.cmd_runner
47+
return self.store.cmd_runner
48+
49+
@cached_property
50+
def store(self):
51+
return Store()

pre_commit/store.py

Lines changed: 97 additions & 0 deletions

0 commit comments

Comments
 (0)