Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions pre_commit/clientlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,39 @@ def check(self, dct: dict[str, Any]) -> None:
raise cfgv.ValidationError(f'{self.key!r} cannot be overridden')


class PythonLockfile(NamedTuple):
key: str
default: str | None

def check(self, dct: dict[str, Any]) -> None:
if self.key not in dct:
return

with cfgv.validate_context(f'At key: {self.key}'):
cfgv.check_string(dct[self.key])

if dct.get('additional_dependencies'):
raise cfgv.ValidationError(
f'{self.key!r} cannot be combined with '
f"'additional_dependencies'",
)

if (
'language' in dct and
_translate_language(dct['language']) != 'python'
):
raise cfgv.ValidationError(
f'{self.key!r} is only supported for language: python',
)

def apply_default(self, dct: dict[str, Any]) -> None:
if self.default is not None:
dct.setdefault(self.key, self.default)

def remove_default(self, dct: dict[str, Any]) -> None:
raise NotImplementedError


_COMMON_HOOK_WARNINGS = (
OptionalSensibleRegexAtHook('files', cfgv.check_string),
OptionalSensibleRegexAtHook('exclude', cfgv.check_string),
Expand Down Expand Up @@ -454,12 +487,14 @@ def check(self, dct: dict[str, Any]) -> None:
),
StagesMigrationNoDefault('stages', []),
LanguageMigration('language', cfgv.check_one_of(language_names)), # remove
PythonLockfile('python_lockfile', None),
*_COMMON_HOOK_WARNINGS,
)
LOCAL_HOOK_DICT = cfgv.Map(
'Hook', 'id',

*MANIFEST_HOOK_DICT.items,
PythonLockfile('python_lockfile', ''),
*_COMMON_HOOK_WARNINGS,
)
CONFIG_REPO_DICT = cfgv.Map(
Expand Down
27 changes: 19 additions & 8 deletions pre_commit/commands/gc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from pre_commit.clientlib import load_manifest
from pre_commit.clientlib import LOCAL
from pre_commit.clientlib import META
from pre_commit.errors import FatalError
from pre_commit.repository import install_key_for_hook
from pre_commit.store import Store
from pre_commit.util import rmtree

Expand All @@ -20,14 +22,19 @@ def _mark_used_repos(
all_repos: dict[tuple[str, str], str],
unused_repos: set[tuple[str, str]],
repo: dict[str, Any],
config_path: str,
) -> None:
if repo['repo'] == META:
return
elif repo['repo'] == LOCAL:
for hook in repo['hooks']:
deps = hook.get('additional_dependencies')
deps, python_lockfile_sha256 = install_key_for_hook(
hook, config_path,
)
unused_repos.discard((
store.db_repo_name(repo['repo'], deps),
store.db_repo_name(
repo['repo'], deps, python_lockfile_sha256,
),
C.LOCAL_REPO_VERSION,
))
else:
Expand All @@ -49,12 +56,14 @@ def _mark_used_repos(
if hook['id'] not in by_id:
continue

deps = hook.get(
'additional_dependencies',
by_id[hook['id']]['additional_dependencies'],
hook_dct = dict(by_id[hook['id']])
hook_dct.update(hook)
deps, python_lockfile_sha256 = install_key_for_hook(
hook_dct, config_path,
)
unused_repos.discard((
store.db_repo_name(repo['repo'], deps), repo['rev'],
store.db_repo_name(repo['repo'], deps, python_lockfile_sha256),
repo['rev'],
))


Expand All @@ -73,12 +82,14 @@ def _gc(store: Store) -> int:
for config_path in configs:
try:
config = load_config(config_path)
except InvalidConfigError:
except (InvalidConfigError, FatalError):
dead_configs.append(config_path)
continue
else:
for repo in config['repos']:
_mark_used_repos(store, all_repos, unused_repos, repo)
_mark_used_repos(
store, all_repos, unused_repos, repo, config_path,
)

paths = [(path,) for path in dead_configs]
db.executemany('DELETE FROM configs WHERE path = ?', paths)
Expand Down
4 changes: 3 additions & 1 deletion pre_commit/commands/install_uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ def install(


def install_hooks(config_file: str, store: Store) -> int:
install_hook_envs(all_hooks(load_config(config_file), store), store)
install_hook_envs(
all_hooks(load_config(config_file), store, config_file), store,
)
return 0


Expand Down
2 changes: 1 addition & 1 deletion pre_commit/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def run(
config = load_config(config_file)
hooks = [
hook
for hook in all_hooks(config, store)
for hook in all_hooks(config, store, config_file)
if not args.hook or hook.id == args.hook or hook.alias == args.hook
if args.hook_stage in hook.stages
]
Expand Down
5 changes: 4 additions & 1 deletion pre_commit/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class Hook(NamedTuple):
types_or: Sequence[str]
exclude_types: Sequence[str]
additional_dependencies: Sequence[str]
python_lockfile: str
python_lockfile_sha256: str
args: Sequence[str]
always_run: bool
fail_fast: bool
Expand All @@ -37,12 +39,13 @@ class Hook(NamedTuple):
verbose: bool

@property
def install_key(self) -> tuple[Prefix, str, str, tuple[str, ...]]:
def install_key(self) -> tuple[Prefix, str, str, tuple[str, ...], str]:
return (
self.prefix,
self.language,
self.language_version,
tuple(self.additional_dependencies),
self.python_lockfile_sha256,
)

@classmethod
Expand Down
26 changes: 26 additions & 0 deletions pre_commit/languages/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,29 @@ def install_environment(
cmd_output_b(*venv_cmd, cwd='/')
with in_env(prefix, version):
lang_base.setup_cmd(prefix, install_cmd)


def install_environment_locked(
prefix: Prefix,
version: str,
lockfile: str,
) -> None:
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
venv_cmd = [sys.executable, '-mvirtualenv', envdir]
python = norm_version(version)
if python is not None:
venv_cmd.extend(('-p', python))

cmd_output_b(*venv_cmd, cwd='/')
with in_env(prefix, version):
lang_base.setup_cmd(
prefix,
('python', '-mpip', 'install', '--require-hashes', '-r', lockfile),
)
lang_base.setup_cmd(
prefix,
(
'python', '-mpip', 'install',
'--no-deps', '--no-build-isolation', '.',
),
)
2 changes: 1 addition & 1 deletion pre_commit/meta_hooks/check_hooks_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def check_all_hooks_match_files(config_file: str) -> int:
)
retv = 0

for hook in all_hooks(config, Store()):
for hook in all_hooks(config, Store(), config_file):
if hook.always_run or hook.language == 'fail':
continue
elif not any(classifier.filenames_for_hook(hook)):
Expand Down
Loading
Loading