Adding upstream version 4.0.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
0de0fde28c
commit
c4faf5b6cb
44 changed files with 596 additions and 105 deletions
|
@ -44,7 +44,5 @@ languages: dict[str, Language] = {
|
|||
'script': script,
|
||||
'swift': swift,
|
||||
'system': system,
|
||||
# TODO: fully deprecate `python_venv`
|
||||
'python_venv': python,
|
||||
}
|
||||
language_names = sorted(languages)
|
||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import functools
|
||||
import logging
|
||||
import os.path
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
|
@ -70,6 +71,43 @@ def transform_stage(stage: str) -> str:
|
|||
return _STAGES.get(stage, stage)
|
||||
|
||||
|
||||
MINIMAL_MANIFEST_SCHEMA = cfgv.Array(
|
||||
cfgv.Map(
|
||||
'Hook', 'id',
|
||||
cfgv.Required('id', cfgv.check_string),
|
||||
cfgv.Optional('stages', cfgv.check_array(cfgv.check_string), []),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def warn_for_stages_on_repo_init(repo: str, directory: str) -> None:
|
||||
try:
|
||||
manifest = cfgv.load_from_filename(
|
||||
os.path.join(directory, C.MANIFEST_FILE),
|
||||
schema=MINIMAL_MANIFEST_SCHEMA,
|
||||
load_strategy=yaml_load,
|
||||
exc_tp=InvalidManifestError,
|
||||
)
|
||||
except InvalidManifestError:
|
||||
return # they'll get a better error message when it actually loads!
|
||||
|
||||
legacy_stages = {} # sorted set
|
||||
for hook in manifest:
|
||||
for stage in hook.get('stages', ()):
|
||||
if stage in _STAGES:
|
||||
legacy_stages[stage] = True
|
||||
|
||||
if legacy_stages:
|
||||
logger.warning(
|
||||
f'repo `{repo}` uses deprecated stage names '
|
||||
f'({", ".join(legacy_stages)}) which will be removed in a '
|
||||
f'future version. '
|
||||
f'Hint: often `pre-commit autoupdate --repo {shlex.quote(repo)}` '
|
||||
f'will fix this. '
|
||||
f'if it does not -- consider reporting an issue to that repo.',
|
||||
)
|
||||
|
||||
|
||||
class StagesMigrationNoDefault(NamedTuple):
|
||||
key: str
|
||||
default: Sequence[str]
|
||||
|
@ -99,6 +137,58 @@ class StagesMigration(StagesMigrationNoDefault):
|
|||
super().apply_default(dct)
|
||||
|
||||
|
||||
class DeprecatedStagesWarning(NamedTuple):
|
||||
key: str
|
||||
|
||||
def check(self, dct: dict[str, Any]) -> None:
|
||||
if self.key not in dct:
|
||||
return
|
||||
|
||||
val = dct[self.key]
|
||||
cfgv.check_array(cfgv.check_any)(val)
|
||||
|
||||
legacy_stages = [stage for stage in val if stage in _STAGES]
|
||||
if legacy_stages:
|
||||
logger.warning(
|
||||
f'hook id `{dct["id"]}` uses deprecated stage names '
|
||||
f'({", ".join(legacy_stages)}) which will be removed in a '
|
||||
f'future version. '
|
||||
f'run: `pre-commit migrate-config` to automatically fix this.',
|
||||
)
|
||||
|
||||
def apply_default(self, dct: dict[str, Any]) -> None:
|
||||
pass
|
||||
|
||||
def remove_default(self, dct: dict[str, Any]) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class DeprecatedDefaultStagesWarning(NamedTuple):
|
||||
key: str
|
||||
|
||||
def check(self, dct: dict[str, Any]) -> None:
|
||||
if self.key not in dct:
|
||||
return
|
||||
|
||||
val = dct[self.key]
|
||||
cfgv.check_array(cfgv.check_any)(val)
|
||||
|
||||
legacy_stages = [stage for stage in val if stage in _STAGES]
|
||||
if legacy_stages:
|
||||
logger.warning(
|
||||
f'top-level `default_stages` uses deprecated stage names '
|
||||
f'({", ".join(legacy_stages)}) which will be removed in a '
|
||||
f'future version. '
|
||||
f'run: `pre-commit migrate-config` to automatically fix this.',
|
||||
)
|
||||
|
||||
def apply_default(self, dct: dict[str, Any]) -> None:
|
||||
pass
|
||||
|
||||
def remove_default(self, dct: dict[str, Any]) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
MANIFEST_HOOK_DICT = cfgv.Map(
|
||||
'Hook', 'id',
|
||||
|
||||
|
@ -267,6 +357,12 @@ class NotAllowed(cfgv.OptionalNoDefault):
|
|||
raise cfgv.ValidationError(f'{self.key!r} cannot be overridden')
|
||||
|
||||
|
||||
_COMMON_HOOK_WARNINGS = (
|
||||
OptionalSensibleRegexAtHook('files', cfgv.check_string),
|
||||
OptionalSensibleRegexAtHook('exclude', cfgv.check_string),
|
||||
DeprecatedStagesWarning('stages'),
|
||||
)
|
||||
|
||||
META_HOOK_DICT = cfgv.Map(
|
||||
'Hook', 'id',
|
||||
cfgv.Required('id', cfgv.check_string),
|
||||
|
@ -289,6 +385,7 @@ META_HOOK_DICT = cfgv.Map(
|
|||
item
|
||||
for item in MANIFEST_HOOK_DICT.items
|
||||
),
|
||||
*_COMMON_HOOK_WARNINGS,
|
||||
)
|
||||
CONFIG_HOOK_DICT = cfgv.Map(
|
||||
'Hook', 'id',
|
||||
|
@ -306,16 +403,13 @@ CONFIG_HOOK_DICT = cfgv.Map(
|
|||
if item.key != 'stages'
|
||||
),
|
||||
StagesMigrationNoDefault('stages', []),
|
||||
OptionalSensibleRegexAtHook('files', cfgv.check_string),
|
||||
OptionalSensibleRegexAtHook('exclude', cfgv.check_string),
|
||||
*_COMMON_HOOK_WARNINGS,
|
||||
)
|
||||
LOCAL_HOOK_DICT = cfgv.Map(
|
||||
'Hook', 'id',
|
||||
|
||||
*MANIFEST_HOOK_DICT.items,
|
||||
|
||||
OptionalSensibleRegexAtHook('files', cfgv.check_string),
|
||||
OptionalSensibleRegexAtHook('exclude', cfgv.check_string),
|
||||
*_COMMON_HOOK_WARNINGS,
|
||||
)
|
||||
CONFIG_REPO_DICT = cfgv.Map(
|
||||
'Repository', 'repo',
|
||||
|
@ -368,6 +462,7 @@ CONFIG_SCHEMA = cfgv.Map(
|
|||
'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
|
||||
),
|
||||
StagesMigration('default_stages', STAGES),
|
||||
DeprecatedDefaultStagesWarning('default_stages'),
|
||||
cfgv.Optional('files', check_string_regex, ''),
|
||||
cfgv.Optional('exclude', check_string_regex, '^$'),
|
||||
cfgv.Optional('fail_fast', cfgv.check_bool, False),
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import functools
|
||||
import itertools
|
||||
import textwrap
|
||||
from typing import Callable
|
||||
|
||||
import cfgv
|
||||
import yaml
|
||||
from yaml.nodes import ScalarNode
|
||||
|
||||
from pre_commit.clientlib import InvalidConfigError
|
||||
from pre_commit.yaml import yaml_compose
|
||||
from pre_commit.yaml import yaml_load
|
||||
from pre_commit.yaml_rewrite import MappingKey
|
||||
from pre_commit.yaml_rewrite import MappingValue
|
||||
from pre_commit.yaml_rewrite import match
|
||||
from pre_commit.yaml_rewrite import SequenceItem
|
||||
|
||||
|
||||
def _is_header_line(line: str) -> bool:
|
||||
|
@ -38,16 +46,69 @@ def _migrate_map(contents: str) -> str:
|
|||
return contents
|
||||
|
||||
|
||||
def _migrate_sha_to_rev(contents: str) -> str:
|
||||
return re.sub(r'(\n\s+)sha:', r'\1rev:', contents)
|
||||
def _preserve_style(n: ScalarNode, *, s: str) -> str:
|
||||
style = n.style or ''
|
||||
return f'{style}{s}{style}'
|
||||
|
||||
|
||||
def _migrate_python_venv(contents: str) -> str:
|
||||
return re.sub(
|
||||
r'(\n\s+)language: python_venv\b',
|
||||
r'\1language: python',
|
||||
contents,
|
||||
def _fix_stage(n: ScalarNode) -> str:
|
||||
return _preserve_style(n, s=f'pre-{n.value}')
|
||||
|
||||
|
||||
def _migrate_composed(contents: str) -> str:
|
||||
tree = yaml_compose(contents)
|
||||
rewrites: list[tuple[ScalarNode, Callable[[ScalarNode], str]]] = []
|
||||
|
||||
# sha -> rev
|
||||
sha_to_rev_replace = functools.partial(_preserve_style, s='rev')
|
||||
sha_to_rev_matcher = (
|
||||
MappingValue('repos'),
|
||||
SequenceItem(),
|
||||
MappingKey('sha'),
|
||||
)
|
||||
for node in match(tree, sha_to_rev_matcher):
|
||||
rewrites.append((node, sha_to_rev_replace))
|
||||
|
||||
# python_venv -> python
|
||||
language_matcher = (
|
||||
MappingValue('repos'),
|
||||
SequenceItem(),
|
||||
MappingValue('hooks'),
|
||||
SequenceItem(),
|
||||
MappingValue('language'),
|
||||
)
|
||||
python_venv_replace = functools.partial(_preserve_style, s='python')
|
||||
for node in match(tree, language_matcher):
|
||||
if node.value == 'python_venv':
|
||||
rewrites.append((node, python_venv_replace))
|
||||
|
||||
# stages rewrites
|
||||
default_stages_matcher = (MappingValue('default_stages'), SequenceItem())
|
||||
default_stages_match = match(tree, default_stages_matcher)
|
||||
hook_stages_matcher = (
|
||||
MappingValue('repos'),
|
||||
SequenceItem(),
|
||||
MappingValue('hooks'),
|
||||
SequenceItem(),
|
||||
MappingValue('stages'),
|
||||
SequenceItem(),
|
||||
)
|
||||
hook_stages_match = match(tree, hook_stages_matcher)
|
||||
for node in itertools.chain(default_stages_match, hook_stages_match):
|
||||
if node.value in {'commit', 'push', 'merge-commit'}:
|
||||
rewrites.append((node, _fix_stage))
|
||||
|
||||
rewrites.sort(reverse=True, key=lambda nf: nf[0].start_mark.index)
|
||||
|
||||
src_parts = []
|
||||
end: int | None = None
|
||||
for node, func in rewrites:
|
||||
src_parts.append(contents[node.end_mark.index:end])
|
||||
src_parts.append(func(node))
|
||||
end = node.start_mark.index
|
||||
src_parts.append(contents[:end])
|
||||
src_parts.reverse()
|
||||
return ''.join(src_parts)
|
||||
|
||||
|
||||
def migrate_config(config_file: str, quiet: bool = False) -> int:
|
||||
|
@ -62,8 +123,7 @@ def migrate_config(config_file: str, quiet: bool = False) -> int:
|
|||
raise cfgv.ValidationError(str(e))
|
||||
|
||||
contents = _migrate_map(contents)
|
||||
contents = _migrate_sha_to_rev(contents)
|
||||
contents = _migrate_python_venv(contents)
|
||||
contents = _migrate_composed(contents)
|
||||
|
||||
if contents != orig_contents:
|
||||
with open(config_file, 'w') as f:
|
||||
|
|
|
@ -61,7 +61,7 @@ def filter_by_include_exclude(
|
|||
names: Iterable[str],
|
||||
include: str,
|
||||
exclude: str,
|
||||
) -> Generator[str, None, None]:
|
||||
) -> Generator[str]:
|
||||
include_re, exclude_re = re.compile(include), re.compile(exclude)
|
||||
return (
|
||||
filename for filename in names
|
||||
|
@ -84,7 +84,7 @@ class Classifier:
|
|||
types: Iterable[str],
|
||||
types_or: Iterable[str],
|
||||
exclude_types: Iterable[str],
|
||||
) -> Generator[str, None, None]:
|
||||
) -> Generator[str]:
|
||||
types = frozenset(types)
|
||||
types_or = frozenset(types_or)
|
||||
exclude_types = frozenset(exclude_types)
|
||||
|
@ -97,7 +97,7 @@ class Classifier:
|
|||
):
|
||||
yield filename
|
||||
|
||||
def filenames_for_hook(self, hook: Hook) -> Generator[str, None, None]:
|
||||
def filenames_for_hook(self, hook: Hook) -> Generator[str]:
|
||||
return self.by_types(
|
||||
filter_by_include_exclude(
|
||||
self.filenames,
|
||||
|
|
|
@ -33,7 +33,7 @@ def format_env(parts: SubstitutionT, env: MutableMapping[str, str]) -> str:
|
|||
def envcontext(
|
||||
patch: PatchesT,
|
||||
_env: MutableMapping[str, str] | None = None,
|
||||
) -> Generator[None, None, None]:
|
||||
) -> Generator[None]:
|
||||
"""In this context, `os.environ` is modified according to `patch`.
|
||||
|
||||
`patch` is an iterable of 2-tuples (key, value):
|
||||
|
|
|
@ -68,7 +68,7 @@ def _log_and_exit(
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def error_handler() -> Generator[None, None, None]:
|
||||
def error_handler() -> Generator[None]:
|
||||
try:
|
||||
yield
|
||||
except (Exception, KeyboardInterrupt) as e:
|
||||
|
|
|
@ -20,7 +20,7 @@ if sys.platform == 'win32': # pragma: no cover (windows)
|
|||
def _locked(
|
||||
fileno: int,
|
||||
blocked_cb: Callable[[], None],
|
||||
) -> Generator[None, None, None]:
|
||||
) -> Generator[None]:
|
||||
try:
|
||||
msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region)
|
||||
except OSError:
|
||||
|
@ -53,7 +53,7 @@ else: # pragma: win32 no cover
|
|||
def _locked(
|
||||
fileno: int,
|
||||
blocked_cb: Callable[[], None],
|
||||
) -> Generator[None, None, None]:
|
||||
) -> Generator[None]:
|
||||
try:
|
||||
fcntl.flock(fileno, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except OSError: # pragma: no cover (tests are single-threaded)
|
||||
|
@ -69,7 +69,7 @@ else: # pragma: win32 no cover
|
|||
def lock(
|
||||
path: str,
|
||||
blocked_cb: Callable[[], None],
|
||||
) -> Generator[None, None, None]:
|
||||
) -> Generator[None]:
|
||||
with open(path, 'a+') as f:
|
||||
with _locked(f.fileno(), blocked_cb):
|
||||
yield
|
||||
|
|
|
@ -127,7 +127,7 @@ def no_install(
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def no_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def no_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
yield
|
||||
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ def get_env_patch(env: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -70,7 +70,7 @@ def get_env_patch(target_dir: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -29,7 +29,7 @@ def get_env_patch(venv: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -30,14 +30,14 @@ def get_env_patch(venv: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _nuget_config_no_sources() -> Generator[str, None, None]:
|
||||
def _nuget_config_no_sources() -> Generator[str]:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
nuget_config = os.path.join(tmpdir, 'nuget.config')
|
||||
with open(nuget_config, 'w') as f:
|
||||
|
|
|
@ -121,7 +121,7 @@ def _install_go(version: str, dest: str) -> None:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir, version)):
|
||||
yield
|
||||
|
|
|
@ -24,7 +24,7 @@ def get_env_patch(target_dir: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -44,7 +44,7 @@ def get_env_patch(d: str) -> PatchesT: # pragma: win32 no cover
|
|||
|
||||
|
||||
@contextlib.contextmanager # pragma: win32 no cover
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -59,7 +59,7 @@ def get_env_patch(venv: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -33,7 +33,7 @@ def get_env_patch(venv: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -152,7 +152,7 @@ def norm_version(version: str) -> str | None:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -85,7 +85,7 @@ def health_check(prefix: Prefix, version: str) -> str | None:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _r_code_in_tempfile(code: str) -> Generator[str, None, None]:
|
||||
def _r_code_in_tempfile(code: str) -> Generator[str]:
|
||||
"""
|
||||
To avoid quoting and escaping issues, avoid `Rscript [options] -e {expr}`
|
||||
but use `Rscript [options] path/to/file_with_expr.R`
|
||||
|
@ -105,7 +105,7 @@ def get_env_patch(venv: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -73,7 +73,7 @@ def get_env_patch(
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir, version)):
|
||||
yield
|
||||
|
|
|
@ -61,7 +61,7 @@ def get_env_patch(target_dir: str, version: str) -> PatchesT:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir, version)):
|
||||
yield
|
||||
|
|
|
@ -27,7 +27,7 @@ def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover
|
|||
|
||||
|
||||
@contextlib.contextmanager # pragma: win32 no cover
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
|
||||
def in_env(prefix: Prefix, version: str) -> Generator[None]:
|
||||
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
|
||||
with envcontext(get_env_patch(envdir)):
|
||||
yield
|
||||
|
|
|
@ -32,7 +32,7 @@ class LoggingHandler(logging.Handler):
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def logging_handler(use_color: bool) -> Generator[None, None, None]:
|
||||
def logging_handler(use_color: bool) -> Generator[None]:
|
||||
handler = LoggingHandler(use_color)
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
from collections.abc import Sequence
|
||||
from typing import Any
|
||||
|
||||
|
@ -68,14 +67,6 @@ def _hook_install(hook: Hook) -> None:
|
|||
logger.info('Once installed this environment will be reused.')
|
||||
logger.info('This may take a few minutes...')
|
||||
|
||||
if hook.language == 'python_venv':
|
||||
logger.warning(
|
||||
f'`repo: {hook.src}` uses deprecated `language: python_venv`. '
|
||||
f'This is an alias for `language: python`. '
|
||||
f'Often `pre-commit autoupdate --repo {shlex.quote(hook.src)}` '
|
||||
f'will fix this.',
|
||||
)
|
||||
|
||||
lang = languages[hook.language]
|
||||
assert lang.ENVIRONMENT_DIR is not None
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -33,7 +33,7 @@ def _git_apply(patch: str) -> None:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _intent_to_add_cleared() -> Generator[None, None, None]:
|
||||
def _intent_to_add_cleared() -> Generator[None]:
|
||||
intent_to_add = git.intent_to_add_files()
|
||||
if intent_to_add:
|
||||
logger.warning('Unstaged intent-to-add files detected.')
|
||||
|
@ -48,7 +48,7 @@ def _intent_to_add_cleared() -> Generator[None, None, None]:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
|
||||
def _unstaged_changes_cleared(patch_dir: str) -> Generator[None]:
|
||||
tree = cmd_output('git', 'write-tree')[1].strip()
|
||||
diff_cmd = (
|
||||
'git', 'diff-index', '--ignore-submodules', '--binary',
|
||||
|
@ -105,7 +105,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def staged_files_only(patch_dir: str) -> Generator[None, None, None]:
|
||||
def staged_files_only(patch_dir: str) -> Generator[None]:
|
||||
"""Clear any unstaged changes from the git working directory inside this
|
||||
context.
|
||||
"""
|
||||
|
|
|
@ -10,6 +10,7 @@ from collections.abc import Sequence
|
|||
from typing import Callable
|
||||
|
||||
import pre_commit.constants as C
|
||||
from pre_commit import clientlib
|
||||
from pre_commit import file_lock
|
||||
from pre_commit import git
|
||||
from pre_commit.util import CalledProcessError
|
||||
|
@ -101,7 +102,7 @@ class Store:
|
|||
os.replace(tmpfile, self.db_path)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def exclusive_lock(self) -> Generator[None, None, None]:
|
||||
def exclusive_lock(self) -> Generator[None]:
|
||||
def blocked_cb() -> None: # pragma: no cover (tests are in-process)
|
||||
logger.info('Locking pre-commit directory')
|
||||
|
||||
|
@ -112,7 +113,7 @@ class Store:
|
|||
def connect(
|
||||
self,
|
||||
db_path: str | None = None,
|
||||
) -> Generator[sqlite3.Connection, None, None]:
|
||||
) -> Generator[sqlite3.Connection]:
|
||||
db_path = db_path or self.db_path
|
||||
# sqlite doesn't close its fd with its contextmanager >.<
|
||||
# contextlib.closing fixes this.
|
||||
|
@ -136,6 +137,7 @@ class Store:
|
|||
deps: Sequence[str],
|
||||
make_strategy: Callable[[str], None],
|
||||
) -> str:
|
||||
original_repo = repo
|
||||
repo = self.db_repo_name(repo, deps)
|
||||
|
||||
def _get_result() -> str | None:
|
||||
|
@ -168,6 +170,9 @@ class Store:
|
|||
'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)',
|
||||
[repo, ref, directory],
|
||||
)
|
||||
|
||||
clientlib.warn_for_stages_on_repo_init(original_repo, directory)
|
||||
|
||||
return directory
|
||||
|
||||
def _complete_clone(self, ref: str, git_cmd: Callable[..., None]) -> None:
|
||||
|
|
|
@ -25,7 +25,7 @@ def force_bytes(exc: Any) -> bytes:
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def clean_path_on_failure(path: str) -> Generator[None, None, None]:
|
||||
def clean_path_on_failure(path: str) -> Generator[None]:
|
||||
"""Cleans up the directory on an exceptional failure."""
|
||||
try:
|
||||
yield
|
||||
|
|
|
@ -120,7 +120,6 @@ def partition(
|
|||
@contextlib.contextmanager
|
||||
def _thread_mapper(maxsize: int) -> Generator[
|
||||
Callable[[Callable[[TArg], TRet], Iterable[TArg]], Iterable[TRet]],
|
||||
None, None,
|
||||
]:
|
||||
if maxsize == 1:
|
||||
yield map
|
||||
|
|
|
@ -6,6 +6,7 @@ from typing import Any
|
|||
import yaml
|
||||
|
||||
Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
|
||||
yaml_compose = functools.partial(yaml.compose, Loader=Loader)
|
||||
yaml_load = functools.partial(yaml.load, Loader=Loader)
|
||||
Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper)
|
||||
|
||||
|
|
52
pre_commit/yaml_rewrite.py
Normal file
52
pre_commit/yaml_rewrite.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
from collections.abc import Iterable
|
||||
from typing import NamedTuple
|
||||
from typing import Protocol
|
||||
|
||||
from yaml.nodes import MappingNode
|
||||
from yaml.nodes import Node
|
||||
from yaml.nodes import ScalarNode
|
||||
from yaml.nodes import SequenceNode
|
||||
|
||||
|
||||
class _Matcher(Protocol):
|
||||
def match(self, n: Node) -> Generator[Node]: ...
|
||||
|
||||
|
||||
class MappingKey(NamedTuple):
|
||||
k: str
|
||||
|
||||
def match(self, n: Node) -> Generator[Node]:
|
||||
if isinstance(n, MappingNode):
|
||||
for k, _ in n.value:
|
||||
if k.value == self.k:
|
||||
yield k
|
||||
|
||||
|
||||
class MappingValue(NamedTuple):
|
||||
k: str
|
||||
|
||||
def match(self, n: Node) -> Generator[Node]:
|
||||
if isinstance(n, MappingNode):
|
||||
for k, v in n.value:
|
||||
if k.value == self.k:
|
||||
yield v
|
||||
|
||||
|
||||
class SequenceItem(NamedTuple):
|
||||
def match(self, n: Node) -> Generator[Node]:
|
||||
if isinstance(n, SequenceNode):
|
||||
yield from n.value
|
||||
|
||||
|
||||
def _match(gen: Iterable[Node], m: _Matcher) -> Iterable[Node]:
|
||||
return (n for src in gen for n in m.match(src))
|
||||
|
||||
|
||||
def match(n: Node, matcher: tuple[_Matcher, ...]) -> Generator[ScalarNode]:
|
||||
gen: Iterable[Node] = (n,)
|
||||
for m in matcher:
|
||||
gen = _match(gen, m)
|
||||
return (n for n in gen if isinstance(n, ScalarNode))
|
Loading…
Add table
Add a link
Reference in a new issue