Merging upstream version 2.18.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
131d7bde70
commit
3396d2e509
116 changed files with 718 additions and 410 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,9 +1,6 @@
|
||||||
*.egg-info
|
*.egg-info
|
||||||
*.py[co]
|
*.py[co]
|
||||||
/.coverage
|
/.coverage
|
||||||
/.mypy_cache
|
|
||||||
/.pytest_cache
|
|
||||||
/.tox
|
/.tox
|
||||||
/dist
|
/dist
|
||||||
/venv*
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
|
@ -4,52 +4,42 @@ repos:
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: check-docstring-first
|
|
||||||
- id: check-json
|
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: debug-statements
|
- id: debug-statements
|
||||||
|
- id: double-quote-string-fixer
|
||||||
- id: name-tests-test
|
- id: name-tests-test
|
||||||
- id: requirements-txt-fixer
|
- id: requirements-txt-fixer
|
||||||
- id: double-quote-string-fixer
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
- repo: https://github.com/PyCQA/flake8
|
rev: v1.20.0
|
||||||
rev: 4.0.1
|
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: setup-cfg-fmt
|
||||||
additional_dependencies: [flake8-typing-imports==1.10.0]
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
|
||||||
rev: v1.6.0
|
|
||||||
hooks:
|
|
||||||
- id: autopep8
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit
|
|
||||||
rev: v2.17.0
|
|
||||||
hooks:
|
|
||||||
- id: validate_manifest
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
|
||||||
rev: v2.31.0
|
|
||||||
hooks:
|
|
||||||
- id: pyupgrade
|
|
||||||
args: [--py36-plus]
|
|
||||||
- repo: https://github.com/asottile/reorder_python_imports
|
- repo: https://github.com/asottile/reorder_python_imports
|
||||||
rev: v2.6.0
|
rev: v3.0.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args: [--py3-plus]
|
exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/)
|
||||||
|
args: [--py37-plus, --add-import, 'from __future__ import annotations']
|
||||||
- repo: https://github.com/asottile/add-trailing-comma
|
- repo: https://github.com/asottile/add-trailing-comma
|
||||||
rev: v2.2.1
|
rev: v2.2.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: add-trailing-comma
|
- id: add-trailing-comma
|
||||||
args: [--py36-plus]
|
args: [--py36-plus]
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v1.20.0
|
rev: v2.31.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: setup-cfg-fmt
|
- id: pyupgrade
|
||||||
|
args: [--py37-plus]
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||||
|
rev: v1.6.0
|
||||||
|
hooks:
|
||||||
|
- id: autopep8
|
||||||
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: 4.0.1
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v0.931
|
rev: v0.942
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
additional_dependencies: [types-all]
|
additional_dependencies: [types-all]
|
||||||
exclude: ^testing/resources/
|
exclude: ^testing/resources/
|
||||||
- repo: meta
|
|
||||||
hooks:
|
|
||||||
- id: check-hooks-apply
|
|
||||||
- id: check-useless-excludes
|
|
||||||
|
|
50
CHANGELOG.md
50
CHANGELOG.md
|
@ -1,3 +1,53 @@
|
||||||
|
2.18.1 - 2022-04-02
|
||||||
|
===================
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix regression for `repo: local` hooks running `python<3.7`
|
||||||
|
- #2324 PR by @asottile.
|
||||||
|
|
||||||
|
2.18.0 - 2022-04-02
|
||||||
|
===================
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Keep `GIT_HTTP_PROXY_AUTHMETHOD` in git environ.
|
||||||
|
- #2272 PR by @VincentBerthier.
|
||||||
|
- #2271 issue by @VincentBerthier.
|
||||||
|
- Support both `cs` and `coursier` executables for coursier hooks.
|
||||||
|
- #2293 PR by @Holzhaus.
|
||||||
|
- Include more information in errors for `language_version` /
|
||||||
|
`additional_dependencies` for languages which do not support them.
|
||||||
|
- #2315 PR by @asottile.
|
||||||
|
- Have autoupdate preferentially pick tags which look like versions when
|
||||||
|
there are multiple equivalent tags.
|
||||||
|
- #2312 PR by @mblayman.
|
||||||
|
- #2311 issue by @mblayman.
|
||||||
|
- Upgrade `ruby-build`.
|
||||||
|
- #2319 PR by @jalessio.
|
||||||
|
- Add top level `default_install_hook_types` which will be installed when
|
||||||
|
`--hook-types` is not specified in `pre-commit install`.
|
||||||
|
- #2322 PR by @asottile.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix typo in help message for `--from-ref` and `--to-ref`.
|
||||||
|
- #2266 PR by @leetrout.
|
||||||
|
- Prioritize binary builds for R dependencies.
|
||||||
|
- #2277 PR by @lorenzwalthert.
|
||||||
|
- Fix handling of git worktrees.
|
||||||
|
- #2252 PR by @daschuer.
|
||||||
|
- Fix handling of `$R_HOME` for R hooks.
|
||||||
|
- #2301 PR by @jeff-m-sullivan.
|
||||||
|
- #2300 issue by @jeff-m-sullivan.
|
||||||
|
- Fix a rare race condition in change stashing.
|
||||||
|
- #2323 PR by @asottile.
|
||||||
|
- #2287 issue by @ian-h-chamberlain.
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
- Remove python3.6 support. Note that pre-commit still supports running hooks
|
||||||
|
written in older versions, but pre-commit itself requires python 3.7+.
|
||||||
|
- #2215 PR by @asottile.
|
||||||
|
- pre-commit has migrated from the `master` branch to `main`.
|
||||||
|
- #2302 PR by @asottile.
|
||||||
|
|
||||||
2.17.0 - 2022-01-18
|
2.17.0 - 2022-01-18
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ language, for example:
|
||||||
|
|
||||||
here are the apis that should be implemented for a language
|
here are the apis that should be implemented for a language
|
||||||
|
|
||||||
Note that these are also documented in [`pre_commit/languages/all.py`](https://github.com/pre-commit/pre-commit/blob/master/pre_commit/languages/all.py)
|
Note that these are also documented in [`pre_commit/languages/all.py`](https://github.com/pre-commit/pre-commit/blob/main/pre_commit/languages/all.py)
|
||||||
|
|
||||||
#### `ENVIRONMENT_DIR`
|
#### `ENVIRONMENT_DIR`
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/pre-commit.pre-commit?branchName=master)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=master)
|
[![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/pre-commit.pre-commit?branchName=main)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=main)
|
||||||
[![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/21/master.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=master)
|
[![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/21/main.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=main)
|
||||||
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit/master.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit/master)
|
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit/main.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit/main)
|
||||||
|
|
||||||
## pre-commit
|
## pre-commit
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
trigger:
|
trigger:
|
||||||
branches:
|
branches:
|
||||||
include: [master, test-me-*]
|
include: [main, test-me-*]
|
||||||
tags:
|
tags:
|
||||||
include: ['*']
|
include: ['*']
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ jobs:
|
||||||
displayName: install R
|
displayName: install R
|
||||||
- template: job--python-tox.yml@asottile
|
- template: job--python-tox.yml@asottile
|
||||||
parameters:
|
parameters:
|
||||||
toxenvs: [pypy3, py36, py37, py38, py39]
|
toxenvs: [py37, py38, py39]
|
||||||
os: linux
|
os: linux
|
||||||
pre_test:
|
pre_test:
|
||||||
- task: UseRubyVersion@0
|
- task: UseRubyVersion@0
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from pre_commit.main import main
|
from pre_commit.main import main
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
|
@ -5,8 +7,6 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
import cfgv
|
import cfgv
|
||||||
|
@ -95,7 +95,7 @@ load_manifest = functools.partial(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int:
|
def validate_manifest_main(argv: Sequence[str] | None = None) -> int:
|
||||||
parser = _make_argparser('Manifest filenames.')
|
parser = _make_argparser('Manifest filenames.')
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ META = 'meta'
|
||||||
|
|
||||||
# should inherit from cfgv.Conditional if sha support is dropped
|
# should inherit from cfgv.Conditional if sha support is dropped
|
||||||
class WarnMutableRev(cfgv.ConditionalOptional):
|
class WarnMutableRev(cfgv.ConditionalOptional):
|
||||||
def check(self, dct: Dict[str, Any]) -> None:
|
def check(self, dct: dict[str, Any]) -> None:
|
||||||
super().check(dct)
|
super().check(dct)
|
||||||
|
|
||||||
if self.key in dct:
|
if self.key in dct:
|
||||||
|
@ -135,7 +135,7 @@ class WarnMutableRev(cfgv.ConditionalOptional):
|
||||||
|
|
||||||
|
|
||||||
class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault):
|
class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault):
|
||||||
def check(self, dct: Dict[str, Any]) -> None:
|
def check(self, dct: dict[str, Any]) -> None:
|
||||||
super().check(dct)
|
super().check(dct)
|
||||||
|
|
||||||
if '/*' in dct.get(self.key, ''):
|
if '/*' in dct.get(self.key, ''):
|
||||||
|
@ -154,7 +154,7 @@ class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault):
|
||||||
|
|
||||||
|
|
||||||
class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault):
|
class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault):
|
||||||
def check(self, dct: Dict[str, Any]) -> None:
|
def check(self, dct: dict[str, Any]) -> None:
|
||||||
super().check(dct)
|
super().check(dct)
|
||||||
|
|
||||||
if '/*' in dct.get(self.key, ''):
|
if '/*' in dct.get(self.key, ''):
|
||||||
|
@ -183,7 +183,7 @@ class MigrateShaToRev:
|
||||||
ensure_absent=True,
|
ensure_absent=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def check(self, dct: Dict[str, Any]) -> None:
|
def check(self, dct: dict[str, Any]) -> None:
|
||||||
if dct.get('repo') in {LOCAL, META}:
|
if dct.get('repo') in {LOCAL, META}:
|
||||||
self._cond('rev').check(dct)
|
self._cond('rev').check(dct)
|
||||||
self._cond('sha').check(dct)
|
self._cond('sha').check(dct)
|
||||||
|
@ -194,7 +194,7 @@ class MigrateShaToRev:
|
||||||
else:
|
else:
|
||||||
self._cond('rev').check(dct)
|
self._cond('rev').check(dct)
|
||||||
|
|
||||||
def apply_default(self, dct: Dict[str, Any]) -> None:
|
def apply_default(self, dct: dict[str, Any]) -> None:
|
||||||
if 'sha' in dct:
|
if 'sha' in dct:
|
||||||
dct['rev'] = dct.pop('sha')
|
dct['rev'] = dct.pop('sha')
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ def _entry(modname: str) -> str:
|
||||||
def warn_unknown_keys_root(
|
def warn_unknown_keys_root(
|
||||||
extra: Sequence[str],
|
extra: Sequence[str],
|
||||||
orig_keys: Sequence[str],
|
orig_keys: Sequence[str],
|
||||||
dct: Dict[str, str],
|
dct: dict[str, str],
|
||||||
) -> None:
|
) -> None:
|
||||||
logger.warning(f'Unexpected key(s) present at root: {", ".join(extra)}')
|
logger.warning(f'Unexpected key(s) present at root: {", ".join(extra)}')
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ def warn_unknown_keys_root(
|
||||||
def warn_unknown_keys_repo(
|
def warn_unknown_keys_repo(
|
||||||
extra: Sequence[str],
|
extra: Sequence[str],
|
||||||
orig_keys: Sequence[str],
|
orig_keys: Sequence[str],
|
||||||
dct: Dict[str, str],
|
dct: dict[str, str],
|
||||||
) -> None:
|
) -> None:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f'Unexpected key(s) present on {dct["repo"]}: {", ".join(extra)}',
|
f'Unexpected key(s) present on {dct["repo"]}: {", ".join(extra)}',
|
||||||
|
@ -253,7 +253,7 @@ _meta = (
|
||||||
|
|
||||||
|
|
||||||
class NotAllowed(cfgv.OptionalNoDefault):
|
class NotAllowed(cfgv.OptionalNoDefault):
|
||||||
def check(self, dct: Dict[str, Any]) -> None:
|
def check(self, dct: dict[str, Any]) -> None:
|
||||||
if self.key in dct:
|
if self.key in dct:
|
||||||
raise cfgv.ValidationError(f'{self.key!r} cannot be overridden')
|
raise cfgv.ValidationError(f'{self.key!r} cannot be overridden')
|
||||||
|
|
||||||
|
@ -336,6 +336,11 @@ CONFIG_SCHEMA = cfgv.Map(
|
||||||
'Config', None,
|
'Config', None,
|
||||||
|
|
||||||
cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
|
cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
|
||||||
|
cfgv.Optional(
|
||||||
|
'default_install_hook_types',
|
||||||
|
cfgv.check_array(cfgv.check_one_of(C.HOOK_TYPES)),
|
||||||
|
['pre-commit'],
|
||||||
|
),
|
||||||
cfgv.OptionalRecurse(
|
cfgv.OptionalRecurse(
|
||||||
'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
|
'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
|
||||||
),
|
),
|
||||||
|
@ -355,6 +360,7 @@ CONFIG_SCHEMA = cfgv.Map(
|
||||||
cfgv.WarnAdditionalKeys(
|
cfgv.WarnAdditionalKeys(
|
||||||
(
|
(
|
||||||
'repos',
|
'repos',
|
||||||
|
'default_install_hook_types',
|
||||||
'default_language_version',
|
'default_language_version',
|
||||||
'default_stages',
|
'default_stages',
|
||||||
'files',
|
'files',
|
||||||
|
@ -377,7 +383,7 @@ class InvalidConfigError(FatalError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def ordered_load_normalize_legacy_config(contents: str) -> Dict[str, Any]:
|
def ordered_load_normalize_legacy_config(contents: str) -> dict[str, Any]:
|
||||||
data = yaml_load(contents)
|
data = yaml_load(contents)
|
||||||
if isinstance(data, list):
|
if isinstance(data, list):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
@ -398,7 +404,7 @@ load_config = functools.partial(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def validate_config_main(argv: Optional[Sequence[str]] = None) -> int:
|
def validate_config_main(argv: Sequence[str] | None = None) -> int:
|
||||||
parser = _make_argparser('Config filenames.')
|
parser = _make_argparser('Config filenames.')
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
|
@ -29,13 +27,13 @@ from pre_commit.util import yaml_load
|
||||||
class RevInfo(NamedTuple):
|
class RevInfo(NamedTuple):
|
||||||
repo: str
|
repo: str
|
||||||
rev: str
|
rev: str
|
||||||
frozen: Optional[str]
|
frozen: str | None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_config(cls, config: Dict[str, Any]) -> 'RevInfo':
|
def from_config(cls, config: dict[str, Any]) -> RevInfo:
|
||||||
return cls(config['repo'], config['rev'], None)
|
return cls(config['repo'], config['rev'], None)
|
||||||
|
|
||||||
def update(self, tags_only: bool, freeze: bool) -> 'RevInfo':
|
def update(self, tags_only: bool, freeze: bool) -> RevInfo:
|
||||||
git_cmd = ('git', *git.NO_FS_MONITOR)
|
git_cmd = ('git', *git.NO_FS_MONITOR)
|
||||||
|
|
||||||
if tags_only:
|
if tags_only:
|
||||||
|
@ -61,6 +59,9 @@ class RevInfo(NamedTuple):
|
||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD')
|
cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD')
|
||||||
rev = cmd_output(*cmd, cwd=tmp)[1].strip()
|
rev = cmd_output(*cmd, cwd=tmp)[1].strip()
|
||||||
|
else:
|
||||||
|
if tags_only:
|
||||||
|
rev = git.get_best_candidate_tag(rev, tmp)
|
||||||
|
|
||||||
frozen = None
|
frozen = None
|
||||||
if freeze:
|
if freeze:
|
||||||
|
@ -76,7 +77,7 @@ class RepositoryCannotBeUpdatedError(RuntimeError):
|
||||||
|
|
||||||
|
|
||||||
def _check_hooks_still_exist_at_rev(
|
def _check_hooks_still_exist_at_rev(
|
||||||
repo_config: Dict[str, Any],
|
repo_config: dict[str, Any],
|
||||||
info: RevInfo,
|
info: RevInfo,
|
||||||
store: Store,
|
store: Store,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -101,9 +102,9 @@ REV_LINE_RE = re.compile(r'^(\s+)rev:(\s*)([\'"]?)([^\s#]+)(.*)(\r?\n)$')
|
||||||
|
|
||||||
def _original_lines(
|
def _original_lines(
|
||||||
path: str,
|
path: str,
|
||||||
rev_infos: List[Optional[RevInfo]],
|
rev_infos: list[RevInfo | None],
|
||||||
retry: bool = False,
|
retry: bool = False,
|
||||||
) -> Tuple[List[str], List[int]]:
|
) -> tuple[list[str], list[int]]:
|
||||||
"""detect `rev:` lines or reformat the file"""
|
"""detect `rev:` lines or reformat the file"""
|
||||||
with open(path, newline='') as f:
|
with open(path, newline='') as f:
|
||||||
original = f.read()
|
original = f.read()
|
||||||
|
@ -120,7 +121,7 @@ def _original_lines(
|
||||||
return _original_lines(path, rev_infos, retry=True)
|
return _original_lines(path, rev_infos, retry=True)
|
||||||
|
|
||||||
|
|
||||||
def _write_new_config(path: str, rev_infos: List[Optional[RevInfo]]) -> None:
|
def _write_new_config(path: str, rev_infos: list[RevInfo | None]) -> None:
|
||||||
lines, idxs = _original_lines(path, rev_infos)
|
lines, idxs = _original_lines(path, rev_infos)
|
||||||
|
|
||||||
for idx, rev_info in zip(idxs, rev_infos):
|
for idx, rev_info in zip(idxs, rev_infos):
|
||||||
|
@ -152,7 +153,7 @@ def autoupdate(
|
||||||
"""Auto-update the pre-commit config to the latest versions of repos."""
|
"""Auto-update the pre-commit config to the latest versions of repos."""
|
||||||
migrate_config(config_file, quiet=True)
|
migrate_config(config_file, quiet=True)
|
||||||
retv = 0
|
retv = 0
|
||||||
rev_infos: List[Optional[RevInfo]] = []
|
rev_infos: list[RevInfo | None] = []
|
||||||
changed = False
|
changed = False
|
||||||
|
|
||||||
config = load_config(config_file)
|
config = load_config(config_file)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
@ -17,9 +16,9 @@ from pre_commit.store import Store
|
||||||
|
|
||||||
def _mark_used_repos(
|
def _mark_used_repos(
|
||||||
store: Store,
|
store: Store,
|
||||||
all_repos: Dict[Tuple[str, str], str],
|
all_repos: dict[tuple[str, str], str],
|
||||||
unused_repos: Set[Tuple[str, str]],
|
unused_repos: set[tuple[str, str]],
|
||||||
repo: Dict[str, Any],
|
repo: dict[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
if repo['repo'] == META:
|
if repo['repo'] == META:
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.commands.run import run
|
from pre_commit.commands.run import run
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -18,7 +18,7 @@ def _run_legacy(
|
||||||
hook_type: str,
|
hook_type: str,
|
||||||
hook_dir: str,
|
hook_dir: str,
|
||||||
args: Sequence[str],
|
args: Sequence[str],
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
if os.environ.get('PRE_COMMIT_RUNNING_LEGACY'):
|
if os.environ.get('PRE_COMMIT_RUNNING_LEGACY'):
|
||||||
raise SystemExit(
|
raise SystemExit(
|
||||||
f"bug: pre-commit's script is installed in migration mode\n"
|
f"bug: pre-commit's script is installed in migration mode\n"
|
||||||
|
@ -69,16 +69,16 @@ def _ns(
|
||||||
color: bool,
|
color: bool,
|
||||||
*,
|
*,
|
||||||
all_files: bool = False,
|
all_files: bool = False,
|
||||||
remote_branch: Optional[str] = None,
|
remote_branch: str | None = None,
|
||||||
local_branch: Optional[str] = None,
|
local_branch: str | None = None,
|
||||||
from_ref: Optional[str] = None,
|
from_ref: str | None = None,
|
||||||
to_ref: Optional[str] = None,
|
to_ref: str | None = None,
|
||||||
remote_name: Optional[str] = None,
|
remote_name: str | None = None,
|
||||||
remote_url: Optional[str] = None,
|
remote_url: str | None = None,
|
||||||
commit_msg_filename: Optional[str] = None,
|
commit_msg_filename: str | None = None,
|
||||||
checkout_type: Optional[str] = None,
|
checkout_type: str | None = None,
|
||||||
is_squash_merge: Optional[str] = None,
|
is_squash_merge: str | None = None,
|
||||||
rewrite_command: Optional[str] = None,
|
rewrite_command: str | None = None,
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
return argparse.Namespace(
|
return argparse.Namespace(
|
||||||
color=color,
|
color=color,
|
||||||
|
@ -109,7 +109,7 @@ def _pre_push_ns(
|
||||||
color: bool,
|
color: bool,
|
||||||
args: Sequence[str],
|
args: Sequence[str],
|
||||||
stdin: bytes,
|
stdin: bytes,
|
||||||
) -> Optional[argparse.Namespace]:
|
) -> argparse.Namespace | None:
|
||||||
remote_name = args[0]
|
remote_name = args[0]
|
||||||
remote_url = args[1]
|
remote_url = args[1]
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ def _run_ns(
|
||||||
color: bool,
|
color: bool,
|
||||||
args: Sequence[str],
|
args: Sequence[str],
|
||||||
stdin: bytes,
|
stdin: bytes,
|
||||||
) -> Optional[argparse.Namespace]:
|
) -> argparse.Namespace | None:
|
||||||
_check_args_length(hook_type, args)
|
_check_args_length(hook_type, args)
|
||||||
if hook_type == 'pre-push':
|
if hook_type == 'pre-push':
|
||||||
return _pre_push_ns(color, args, stdin)
|
return _pre_push_ns(color, args, stdin)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Sequence
|
|
||||||
|
|
||||||
from pre_commit.commands.install_uninstall import install
|
from pre_commit.commands.install_uninstall import install
|
||||||
from pre_commit.store import Store
|
from pre_commit.store import Store
|
||||||
|
@ -14,7 +15,7 @@ def init_templatedir(
|
||||||
config_file: str,
|
config_file: str,
|
||||||
store: Store,
|
store: Store,
|
||||||
directory: str,
|
directory: str,
|
||||||
hook_types: Sequence[str],
|
hook_types: list[str] | None,
|
||||||
skip_on_missing_config: bool = True,
|
skip_on_missing_config: bool = True,
|
||||||
) -> int:
|
) -> int:
|
||||||
install(
|
install(
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
from pre_commit.clientlib import InvalidConfigError
|
||||||
from pre_commit.clientlib import load_config
|
from pre_commit.clientlib import load_config
|
||||||
from pre_commit.repository import all_hooks
|
from pre_commit.repository import all_hooks
|
||||||
from pre_commit.repository import install_hook_envs
|
from pre_commit.repository import install_hook_envs
|
||||||
|
@ -32,11 +32,23 @@ TEMPLATE_START = '# start templated\n'
|
||||||
TEMPLATE_END = '# end templated\n'
|
TEMPLATE_END = '# end templated\n'
|
||||||
|
|
||||||
|
|
||||||
|
def _hook_types(cfg_filename: str, hook_types: list[str] | None) -> list[str]:
|
||||||
|
if hook_types is not None:
|
||||||
|
return hook_types
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
cfg = load_config(cfg_filename)
|
||||||
|
except InvalidConfigError:
|
||||||
|
return ['pre-commit']
|
||||||
|
else:
|
||||||
|
return cfg['default_install_hook_types']
|
||||||
|
|
||||||
|
|
||||||
def _hook_paths(
|
def _hook_paths(
|
||||||
hook_type: str,
|
hook_type: str,
|
||||||
git_dir: Optional[str] = None,
|
git_dir: str | None = None,
|
||||||
) -> Tuple[str, str]:
|
) -> tuple[str, str]:
|
||||||
git_dir = git_dir if git_dir is not None else git.get_git_dir()
|
git_dir = git_dir if git_dir is not None else git.get_git_common_dir()
|
||||||
pth = os.path.join(git_dir, 'hooks', hook_type)
|
pth = os.path.join(git_dir, 'hooks', hook_type)
|
||||||
return pth, f'{pth}.legacy'
|
return pth, f'{pth}.legacy'
|
||||||
|
|
||||||
|
@ -54,7 +66,7 @@ def _install_hook_script(
|
||||||
hook_type: str,
|
hook_type: str,
|
||||||
overwrite: bool = False,
|
overwrite: bool = False,
|
||||||
skip_on_missing_config: bool = False,
|
skip_on_missing_config: bool = False,
|
||||||
git_dir: Optional[str] = None,
|
git_dir: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir)
|
hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir)
|
||||||
|
|
||||||
|
@ -103,11 +115,11 @@ def _install_hook_script(
|
||||||
def install(
|
def install(
|
||||||
config_file: str,
|
config_file: str,
|
||||||
store: Store,
|
store: Store,
|
||||||
hook_types: Sequence[str],
|
hook_types: list[str] | None,
|
||||||
overwrite: bool = False,
|
overwrite: bool = False,
|
||||||
hooks: bool = False,
|
hooks: bool = False,
|
||||||
skip_on_missing_config: bool = False,
|
skip_on_missing_config: bool = False,
|
||||||
git_dir: Optional[str] = None,
|
git_dir: str | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
if git_dir is None and git.has_core_hookpaths_set():
|
if git_dir is None and git.has_core_hookpaths_set():
|
||||||
logger.error(
|
logger.error(
|
||||||
|
@ -116,7 +128,7 @@ def install(
|
||||||
)
|
)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
for hook_type in hook_types:
|
for hook_type in _hook_types(config_file, hook_types):
|
||||||
_install_hook_script(
|
_install_hook_script(
|
||||||
config_file, hook_type,
|
config_file, hook_type,
|
||||||
overwrite=overwrite,
|
overwrite=overwrite,
|
||||||
|
@ -150,7 +162,7 @@ def _uninstall_hook_script(hook_type: str) -> None:
|
||||||
output.write_line(f'Restored previous hooks to {hook_path}')
|
output.write_line(f'Restored previous hooks to {hook_path}')
|
||||||
|
|
||||||
|
|
||||||
def uninstall(hook_types: Sequence[str]) -> int:
|
def uninstall(config_file: str, hook_types: list[str] | None) -> int:
|
||||||
for hook_type in hook_types:
|
for hook_type in _hook_types(config_file, hook_types):
|
||||||
_uninstall_hook_script(hook_type)
|
_uninstall_hook_script(hook_type)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
|
@ -9,12 +11,8 @@ import time
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Collection
|
from typing import Collection
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from identify.identify import tags_from_path
|
from identify.identify import tags_from_path
|
||||||
|
|
||||||
|
@ -62,7 +60,7 @@ def filter_by_include_exclude(
|
||||||
names: Collection[str],
|
names: Collection[str],
|
||||||
include: str,
|
include: str,
|
||||||
exclude: str,
|
exclude: str,
|
||||||
) -> List[str]:
|
) -> list[str]:
|
||||||
include_re, exclude_re = re.compile(include), re.compile(exclude)
|
include_re, exclude_re = re.compile(include), re.compile(exclude)
|
||||||
return [
|
return [
|
||||||
filename for filename in names
|
filename for filename in names
|
||||||
|
@ -76,7 +74,7 @@ class Classifier:
|
||||||
self.filenames = [f for f in filenames if os.path.lexists(f)]
|
self.filenames = [f for f in filenames if os.path.lexists(f)]
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=None)
|
@functools.lru_cache(maxsize=None)
|
||||||
def _types_for_file(self, filename: str) -> Set[str]:
|
def _types_for_file(self, filename: str) -> set[str]:
|
||||||
return tags_from_path(filename)
|
return tags_from_path(filename)
|
||||||
|
|
||||||
def by_types(
|
def by_types(
|
||||||
|
@ -85,7 +83,7 @@ class Classifier:
|
||||||
types: Collection[str],
|
types: Collection[str],
|
||||||
types_or: Collection[str],
|
types_or: Collection[str],
|
||||||
exclude_types: Collection[str],
|
exclude_types: Collection[str],
|
||||||
) -> List[str]:
|
) -> list[str]:
|
||||||
types = frozenset(types)
|
types = frozenset(types)
|
||||||
types_or = frozenset(types_or)
|
types_or = frozenset(types_or)
|
||||||
exclude_types = frozenset(exclude_types)
|
exclude_types = frozenset(exclude_types)
|
||||||
|
@ -100,7 +98,7 @@ class Classifier:
|
||||||
ret.append(filename)
|
ret.append(filename)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def filenames_for_hook(self, hook: Hook) -> Tuple[str, ...]:
|
def filenames_for_hook(self, hook: Hook) -> tuple[str, ...]:
|
||||||
names = self.filenames
|
names = self.filenames
|
||||||
names = filter_by_include_exclude(names, hook.files, hook.exclude)
|
names = filter_by_include_exclude(names, hook.files, hook.exclude)
|
||||||
names = self.by_types(
|
names = self.by_types(
|
||||||
|
@ -117,7 +115,7 @@ class Classifier:
|
||||||
filenames: Collection[str],
|
filenames: Collection[str],
|
||||||
include: str,
|
include: str,
|
||||||
exclude: str,
|
exclude: str,
|
||||||
) -> 'Classifier':
|
) -> Classifier:
|
||||||
# on windows we normalize all filenames to use forward slashes
|
# on windows we normalize all filenames to use forward slashes
|
||||||
# this makes it easier to filter using the `files:` regex
|
# this makes it easier to filter using the `files:` regex
|
||||||
# this also makes improperly quoted shell-based hooks work better
|
# this also makes improperly quoted shell-based hooks work better
|
||||||
|
@ -128,7 +126,7 @@ class Classifier:
|
||||||
return Classifier(filenames)
|
return Classifier(filenames)
|
||||||
|
|
||||||
|
|
||||||
def _get_skips(environ: MutableMapping[str, str]) -> Set[str]:
|
def _get_skips(environ: MutableMapping[str, str]) -> set[str]:
|
||||||
skips = environ.get('SKIP', '')
|
skips = environ.get('SKIP', '')
|
||||||
return {skip.strip() for skip in skips.split(',') if skip.strip()}
|
return {skip.strip() for skip in skips.split(',') if skip.strip()}
|
||||||
|
|
||||||
|
@ -144,12 +142,12 @@ def _subtle_line(s: str, use_color: bool) -> None:
|
||||||
def _run_single_hook(
|
def _run_single_hook(
|
||||||
classifier: Classifier,
|
classifier: Classifier,
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
skips: Set[str],
|
skips: set[str],
|
||||||
cols: int,
|
cols: int,
|
||||||
diff_before: bytes,
|
diff_before: bytes,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
use_color: bool,
|
use_color: bool,
|
||||||
) -> Tuple[bool, bytes]:
|
) -> tuple[bool, bytes]:
|
||||||
filenames = classifier.filenames_for_hook(hook)
|
filenames = classifier.filenames_for_hook(hook)
|
||||||
|
|
||||||
if hook.id in skips or hook.alias in skips:
|
if hook.id in skips or hook.alias in skips:
|
||||||
|
@ -271,9 +269,9 @@ def _get_diff() -> bytes:
|
||||||
|
|
||||||
|
|
||||||
def _run_hooks(
|
def _run_hooks(
|
||||||
config: Dict[str, Any],
|
config: dict[str, Any],
|
||||||
hooks: Sequence[Hook],
|
hooks: Sequence[Hook],
|
||||||
skips: Set[str],
|
skips: set[str],
|
||||||
args: argparse.Namespace,
|
args: argparse.Namespace,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Actually run the hooks."""
|
"""Actually run the hooks."""
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# determine the latest revision? This adds ~200ms from my tests (and is
|
# determine the latest revision? This adds ~200ms from my tests (and is
|
||||||
# significantly faster than https:// or http://). For now, periodically
|
# significantly faster than https:// or http://). For now, periodically
|
||||||
# manually updating the revision is fine.
|
# manually updating the revision is fine.
|
||||||
|
from __future__ import annotations
|
||||||
SAMPLE_CONFIG = '''\
|
SAMPLE_CONFIG = '''\
|
||||||
# See https://pre-commit.com for more information
|
# See https://pre-commit.com for more information
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
|
@ -18,7 +18,7 @@ from pre_commit.xargs import xargs
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _repo_ref(tmpdir: str, repo: str, ref: Optional[str]) -> Tuple[str, str]:
|
def _repo_ref(tmpdir: str, repo: str, ref: str | None) -> tuple[str, str]:
|
||||||
# if `ref` is explicitly passed, use it
|
# if `ref` is explicitly passed, use it
|
||||||
if ref is not None:
|
if ref is not None:
|
||||||
return repo, ref
|
return repo, ref
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info >= (3, 8): # pragma: >=3.8 cover
|
if sys.version_info >= (3, 8): # pragma: >=3.8 cover
|
||||||
|
@ -22,4 +24,10 @@ STAGES = (
|
||||||
'post-rewrite',
|
'post-rewrite',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
HOOK_TYPES = (
|
||||||
|
'pre-commit', 'pre-merge-commit', 'pre-push', 'prepare-commit-msg',
|
||||||
|
'commit-msg', 'post-commit', 'post-checkout', 'post-merge',
|
||||||
|
'post-rewrite',
|
||||||
|
)
|
||||||
|
|
||||||
DEFAULT = 'default'
|
DEFAULT = 'default'
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import enum
|
import enum
|
||||||
import os
|
import os
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ def format_env(parts: SubstitutionT, env: MutableMapping[str, str]) -> str:
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def envcontext(
|
def envcontext(
|
||||||
patch: PatchesT,
|
patch: PatchesT,
|
||||||
_env: Optional[MutableMapping[str, str]] = None,
|
_env: MutableMapping[str, str] | None = None,
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
"""In this context, `os.environ` is modified according to `patch`.
|
"""In this context, `os.environ` is modified according to `patch`.
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
@ -30,7 +33,7 @@ def _log_and_exit(
|
||||||
with contextlib.ExitStack() as ctx:
|
with contextlib.ExitStack() as ctx:
|
||||||
if os.access(storedir, os.W_OK):
|
if os.access(storedir, os.W_OK):
|
||||||
output.write_line(f'Check the log at {log_path}')
|
output.write_line(f'Check the log at {log_path}')
|
||||||
log = ctx.enter_context(open(log_path, 'wb'))
|
log: IO[bytes] = ctx.enter_context(open(log_path, 'wb'))
|
||||||
else: # pragma: win32 no cover
|
else: # pragma: win32 no cover
|
||||||
output.write_line(f'Failed to write to log at {log_path}')
|
output.write_line(f'Failed to write to log at {log_path}')
|
||||||
log = sys.stdout.buffer
|
log = sys.stdout.buffer
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
class FatalError(RuntimeError):
|
class FatalError(RuntimeError):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import sys
|
import sys
|
||||||
|
@ -20,13 +22,11 @@ if sys.platform == 'win32': # pragma: no cover (windows)
|
||||||
blocked_cb: Callable[[], None],
|
blocked_cb: Callable[[], None],
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
try:
|
try:
|
||||||
# TODO: https://github.com/python/typeshed/pull/3607
|
|
||||||
msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region)
|
msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region)
|
||||||
except OSError:
|
except OSError:
|
||||||
blocked_cb()
|
blocked_cb()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# TODO: https://github.com/python/typeshed/pull/3607
|
|
||||||
msvcrt.locking(fileno, msvcrt.LK_LOCK, _region)
|
msvcrt.locking(fileno, msvcrt.LK_LOCK, _region)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
# Locking violation. Returned when the _LK_LOCK or _LK_RLCK
|
# Locking violation. Returned when the _LK_LOCK or _LK_RLCK
|
||||||
|
@ -45,7 +45,6 @@ if sys.platform == 'win32': # pragma: no cover (windows)
|
||||||
# The documentation however states:
|
# The documentation however states:
|
||||||
# "Regions should be locked only briefly and should be unlocked
|
# "Regions should be locked only briefly and should be unlocked
|
||||||
# before closing a file or exiting the program."
|
# before closing a file or exiting the program."
|
||||||
# TODO: https://github.com/python/typeshed/pull/3607
|
|
||||||
msvcrt.locking(fileno, msvcrt.LK_UNLCK, _region)
|
msvcrt.locking(fileno, msvcrt.LK_UNLCK, _region)
|
||||||
else: # pragma: win32 no cover
|
else: # pragma: win32 no cover
|
||||||
import fcntl
|
import fcntl
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
from typing import Optional
|
|
||||||
from typing import Set
|
|
||||||
|
|
||||||
from pre_commit.errors import FatalError
|
from pre_commit.errors import FatalError
|
||||||
from pre_commit.util import CalledProcessError
|
from pre_commit.util import CalledProcessError
|
||||||
|
@ -18,7 +16,7 @@ logger = logging.getLogger(__name__)
|
||||||
NO_FS_MONITOR = ('-c', 'core.useBuiltinFSMonitor=false')
|
NO_FS_MONITOR = ('-c', 'core.useBuiltinFSMonitor=false')
|
||||||
|
|
||||||
|
|
||||||
def zsplit(s: str) -> List[str]:
|
def zsplit(s: str) -> list[str]:
|
||||||
s = s.strip('\0')
|
s = s.strip('\0')
|
||||||
if s:
|
if s:
|
||||||
return s.split('\0')
|
return s.split('\0')
|
||||||
|
@ -27,8 +25,8 @@ def zsplit(s: str) -> List[str]:
|
||||||
|
|
||||||
|
|
||||||
def no_git_env(
|
def no_git_env(
|
||||||
_env: Optional[MutableMapping[str, str]] = None,
|
_env: MutableMapping[str, str] | None = None,
|
||||||
) -> Dict[str, str]:
|
) -> dict[str, str]:
|
||||||
# Too many bugs dealing with environment variables and GIT:
|
# Too many bugs dealing with environment variables and GIT:
|
||||||
# https://github.com/pre-commit/pre-commit/issues/300
|
# https://github.com/pre-commit/pre-commit/issues/300
|
||||||
# In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running
|
# In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running
|
||||||
|
@ -45,6 +43,7 @@ def no_git_env(
|
||||||
k in {
|
k in {
|
||||||
'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO',
|
'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO',
|
||||||
'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT',
|
'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT',
|
||||||
|
'GIT_HTTP_PROXY_AUTHMETHOD',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,13 +57,15 @@ def get_root() -> str:
|
||||||
root = os.path.abspath(
|
root = os.path.abspath(
|
||||||
cmd_output('git', 'rev-parse', '--show-cdup')[1].strip(),
|
cmd_output('git', 'rev-parse', '--show-cdup')[1].strip(),
|
||||||
)
|
)
|
||||||
git_dir = os.path.abspath(get_git_dir())
|
inside_git_dir = cmd_output(
|
||||||
|
'git', 'rev-parse', '--is-inside-git-dir',
|
||||||
|
)[1].strip()
|
||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
raise FatalError(
|
raise FatalError(
|
||||||
'git failed. Is it installed, and are you in a Git repository '
|
'git failed. Is it installed, and are you in a Git repository '
|
||||||
'directory?',
|
'directory?',
|
||||||
)
|
)
|
||||||
if os.path.samefile(root, git_dir):
|
if inside_git_dir != 'false':
|
||||||
raise FatalError(
|
raise FatalError(
|
||||||
'git toplevel unexpectedly empty! make sure you are not '
|
'git toplevel unexpectedly empty! make sure you are not '
|
||||||
'inside the `.git` directory of your repository.',
|
'inside the `.git` directory of your repository.',
|
||||||
|
@ -73,15 +74,25 @@ def get_root() -> str:
|
||||||
|
|
||||||
|
|
||||||
def get_git_dir(git_root: str = '.') -> str:
|
def get_git_dir(git_root: str = '.') -> str:
|
||||||
opts = ('--git-common-dir', '--git-dir')
|
opt = '--git-dir'
|
||||||
_, out, _ = cmd_output('git', 'rev-parse', *opts, cwd=git_root)
|
_, out, _ = cmd_output('git', 'rev-parse', opt, cwd=git_root)
|
||||||
for line, opt in zip(out.splitlines(), opts):
|
git_dir = out.strip()
|
||||||
if line != opt: # pragma: no branch (git < 2.5)
|
if git_dir != opt:
|
||||||
return os.path.normpath(os.path.join(git_root, line))
|
return os.path.normpath(os.path.join(git_root, git_dir))
|
||||||
else:
|
else:
|
||||||
raise AssertionError('unreachable: no git dir')
|
raise AssertionError('unreachable: no git dir')
|
||||||
|
|
||||||
|
|
||||||
|
def get_git_common_dir(git_root: str = '.') -> str:
|
||||||
|
opt = '--git-common-dir'
|
||||||
|
_, out, _ = cmd_output('git', 'rev-parse', opt, cwd=git_root)
|
||||||
|
git_common_dir = out.strip()
|
||||||
|
if git_common_dir != opt:
|
||||||
|
return os.path.normpath(os.path.join(git_root, git_common_dir))
|
||||||
|
else: # pragma: no cover (git < 2.5)
|
||||||
|
return get_git_dir(git_root)
|
||||||
|
|
||||||
|
|
||||||
def get_remote_url(git_root: str) -> str:
|
def get_remote_url(git_root: str) -> str:
|
||||||
_, out, _ = cmd_output('git', 'config', 'remote.origin.url', cwd=git_root)
|
_, out, _ = cmd_output('git', 'config', 'remote.origin.url', cwd=git_root)
|
||||||
return out.strip()
|
return out.strip()
|
||||||
|
@ -95,7 +106,7 @@ def is_in_merge_conflict() -> bool:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_merge_msg_for_conflicts(merge_msg: bytes) -> List[str]:
|
def parse_merge_msg_for_conflicts(merge_msg: bytes) -> list[str]:
|
||||||
# Conflicted files start with tabs
|
# Conflicted files start with tabs
|
||||||
return [
|
return [
|
||||||
line.lstrip(b'#').strip().decode()
|
line.lstrip(b'#').strip().decode()
|
||||||
|
@ -105,7 +116,7 @@ def parse_merge_msg_for_conflicts(merge_msg: bytes) -> List[str]:
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_conflicted_files() -> Set[str]:
|
def get_conflicted_files() -> set[str]:
|
||||||
logger.info('Checking merge-conflict files only.')
|
logger.info('Checking merge-conflict files only.')
|
||||||
# Need to get the conflicted files from the MERGE_MSG because they could
|
# Need to get the conflicted files from the MERGE_MSG because they could
|
||||||
# have resolved the conflict by choosing one side or the other
|
# have resolved the conflict by choosing one side or the other
|
||||||
|
@ -126,7 +137,7 @@ def get_conflicted_files() -> Set[str]:
|
||||||
return set(merge_conflict_filenames) | set(merge_diff_filenames)
|
return set(merge_conflict_filenames) | set(merge_diff_filenames)
|
||||||
|
|
||||||
|
|
||||||
def get_staged_files(cwd: Optional[str] = None) -> List[str]:
|
def get_staged_files(cwd: str | None = None) -> list[str]:
|
||||||
return zsplit(
|
return zsplit(
|
||||||
cmd_output(
|
cmd_output(
|
||||||
'git', 'diff', '--staged', '--name-only', '--no-ext-diff', '-z',
|
'git', 'diff', '--staged', '--name-only', '--no-ext-diff', '-z',
|
||||||
|
@ -137,7 +148,7 @@ def get_staged_files(cwd: Optional[str] = None) -> List[str]:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def intent_to_add_files() -> List[str]:
|
def intent_to_add_files() -> list[str]:
|
||||||
_, stdout, _ = cmd_output(
|
_, stdout, _ = cmd_output(
|
||||||
'git', 'status', '--ignore-submodules', '--porcelain', '-z',
|
'git', 'status', '--ignore-submodules', '--porcelain', '-z',
|
||||||
)
|
)
|
||||||
|
@ -153,11 +164,11 @@ def intent_to_add_files() -> List[str]:
|
||||||
return intent_to_add
|
return intent_to_add
|
||||||
|
|
||||||
|
|
||||||
def get_all_files() -> List[str]:
|
def get_all_files() -> list[str]:
|
||||||
return zsplit(cmd_output('git', 'ls-files', '-z')[1])
|
return zsplit(cmd_output('git', 'ls-files', '-z')[1])
|
||||||
|
|
||||||
|
|
||||||
def get_changed_files(old: str, new: str) -> List[str]:
|
def get_changed_files(old: str, new: str) -> list[str]:
|
||||||
diff_cmd = ('git', 'diff', '--name-only', '--no-ext-diff', '-z')
|
diff_cmd = ('git', 'diff', '--name-only', '--no-ext-diff', '-z')
|
||||||
try:
|
try:
|
||||||
_, out, _ = cmd_output(*diff_cmd, f'{old}...{new}')
|
_, out, _ = cmd_output(*diff_cmd, f'{old}...{new}')
|
||||||
|
@ -230,3 +241,18 @@ def check_for_cygwin_mismatch() -> None:
|
||||||
f' - python {exe_type[is_cygwin_python]}\n'
|
f' - python {exe_type[is_cygwin_python]}\n'
|
||||||
f' - git {exe_type[is_cygwin_git]}\n',
|
f' - git {exe_type[is_cygwin_git]}\n',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_best_candidate_tag(rev: str, git_repo: str) -> str:
|
||||||
|
"""Get the best tag candidate.
|
||||||
|
|
||||||
|
Multiple tags can exist on a SHA. Sometimes a moving tag is attached
|
||||||
|
to a version tag. Try to pick the tag that looks like a version.
|
||||||
|
"""
|
||||||
|
tags = cmd_output(
|
||||||
|
'git', *NO_FS_MONITOR, 'tag', '--points-at', rev, cwd=git_repo,
|
||||||
|
)[1].splitlines()
|
||||||
|
for tag in tags:
|
||||||
|
if '.' in tag:
|
||||||
|
return tag
|
||||||
|
return rev
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import shlex
|
import shlex
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.prefix import Prefix
|
from pre_commit.prefix import Prefix
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@ class Hook(NamedTuple):
|
||||||
verbose: bool
|
verbose: bool
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cmd(self) -> Tuple[str, ...]:
|
def cmd(self) -> tuple[str, ...]:
|
||||||
return (*shlex.split(self.entry), *self.args)
|
return (*shlex.split(self.entry), *self.args)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def install_key(self) -> Tuple[Prefix, str, str, Tuple[str, ...]]:
|
def install_key(self) -> tuple[Prefix, str, str, tuple[str, ...]]:
|
||||||
return (
|
return (
|
||||||
self.prefix,
|
self.prefix,
|
||||||
self.language,
|
self.language,
|
||||||
|
@ -51,7 +51,7 @@ class Hook(NamedTuple):
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, src: str, prefix: Prefix, dct: Dict[str, Any]) -> 'Hook':
|
def create(cls, src: str, prefix: Prefix, dct: dict[str, Any]) -> Hook:
|
||||||
# TODO: have cfgv do this (?)
|
# TODO: have cfgv do this (?)
|
||||||
extra_keys = set(dct) - _KEYS
|
extra_keys = set(dct) - _KEYS
|
||||||
if extra_keys:
|
if extra_keys:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import conda
|
from pre_commit.languages import conda
|
||||||
|
@ -30,7 +30,7 @@ from pre_commit.prefix import Prefix
|
||||||
class Language(NamedTuple):
|
class Language(NamedTuple):
|
||||||
name: str
|
name: str
|
||||||
# Use `None` for no installation / environment
|
# Use `None` for no installation / environment
|
||||||
ENVIRONMENT_DIR: Optional[str]
|
ENVIRONMENT_DIR: str | None
|
||||||
# return a value to replace `'default` for `language_version`
|
# return a value to replace `'default` for `language_version`
|
||||||
get_default_version: Callable[[], str]
|
get_default_version: Callable[[], str]
|
||||||
# return whether the environment is healthy (or should be rebuilt)
|
# return whether the environment is healthy (or should be rebuilt)
|
||||||
|
@ -38,7 +38,7 @@ class Language(NamedTuple):
|
||||||
# install a repository for the given language and language_version
|
# install a repository for the given language and language_version
|
||||||
install_environment: Callable[[Prefix, str, Sequence[str]], None]
|
install_environment: Callable[[Prefix, str, Sequence[str]], None]
|
||||||
# execute a hook and return the exit code and output
|
# execute a hook and return the exit code and output
|
||||||
run_hook: 'Callable[[Hook, Sequence[str], bool], Tuple[int, bytes]]'
|
run_hook: Callable[[Hook, Sequence[str], bool], tuple[int, bytes]]
|
||||||
|
|
||||||
|
|
||||||
# TODO: back to modules + Protocol: https://github.com/python/mypy/issues/5018
|
# TODO: back to modules + Protocol: https://github.com/python/mypy/issues/5018
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
from pre_commit.envcontext import PatchesT
|
from pre_commit.envcontext import PatchesT
|
||||||
|
@ -86,7 +87,7 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
# TODO: Some rare commands need to be run using `conda run` but mostly we
|
# TODO: Some rare commands need to be run using `conda run` but mostly we
|
||||||
# can run them without which is much quicker and produces a better
|
# can run them without which is much quicker and produces a better
|
||||||
# output.
|
# output.
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
from pre_commit.envcontext import PatchesT
|
from pre_commit.envcontext import PatchesT
|
||||||
from pre_commit.envcontext import Var
|
from pre_commit.envcontext import Var
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import helpers
|
from pre_commit.languages import helpers
|
||||||
|
from pre_commit.parse_shebang import find_executable
|
||||||
from pre_commit.prefix import Prefix
|
from pre_commit.prefix import Prefix
|
||||||
from pre_commit.util import clean_path_on_failure
|
from pre_commit.util import clean_path_on_failure
|
||||||
|
|
||||||
|
@ -26,6 +28,14 @@ def install_environment(
|
||||||
helpers.assert_version_default('coursier', version)
|
helpers.assert_version_default('coursier', version)
|
||||||
helpers.assert_no_additional_deps('coursier', additional_dependencies)
|
helpers.assert_no_additional_deps('coursier', additional_dependencies)
|
||||||
|
|
||||||
|
# Support both possible executable names (either "cs" or "coursier")
|
||||||
|
executable = find_executable('cs') or find_executable('coursier')
|
||||||
|
if executable is None:
|
||||||
|
raise AssertionError(
|
||||||
|
'pre-commit requires system-installed "cs" or "coursier" '
|
||||||
|
'executables in the application search path',
|
||||||
|
)
|
||||||
|
|
||||||
envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version))
|
envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version))
|
||||||
channel = prefix.path('.pre-commit-channel')
|
channel = prefix.path('.pre-commit-channel')
|
||||||
with clean_path_on_failure(envdir):
|
with clean_path_on_failure(envdir):
|
||||||
|
@ -35,7 +45,7 @@ def install_environment(
|
||||||
helpers.run_setup_cmd(
|
helpers.run_setup_cmd(
|
||||||
prefix,
|
prefix,
|
||||||
(
|
(
|
||||||
'cs',
|
executable,
|
||||||
'install',
|
'install',
|
||||||
'--default-channels=false',
|
'--default-channels=false',
|
||||||
f'--channel={channel}',
|
f'--channel={channel}',
|
||||||
|
@ -66,6 +76,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]: # pragma: win32 no cover
|
) -> tuple[int, bytes]: # pragma: win32 no cover
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -76,7 +77,7 @@ def install_environment(
|
||||||
with tempfile.TemporaryDirectory() as dep_tmp:
|
with tempfile.TemporaryDirectory() as dep_tmp:
|
||||||
dep, _, version = dep_s.partition(':')
|
dep, _, version = dep_s.partition(':')
|
||||||
if version:
|
if version:
|
||||||
dep_cmd: Tuple[str, ...] = (dep, '--version', version)
|
dep_cmd: tuple[str, ...] = (dep, '--version', version)
|
||||||
else:
|
else:
|
||||||
dep_cmd = (dep,)
|
dep_cmd = (dep,)
|
||||||
|
|
||||||
|
@ -104,6 +105,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
|
@ -76,7 +77,7 @@ def build_docker_image(
|
||||||
*,
|
*,
|
||||||
pull: bool,
|
pull: bool,
|
||||||
) -> None: # pragma: win32 no cover
|
) -> None: # pragma: win32 no cover
|
||||||
cmd: Tuple[str, ...] = (
|
cmd: tuple[str, ...] = (
|
||||||
'docker', 'build',
|
'docker', 'build',
|
||||||
'--tag', docker_tag(prefix),
|
'--tag', docker_tag(prefix),
|
||||||
'--label', PRE_COMMIT_LABEL,
|
'--label', PRE_COMMIT_LABEL,
|
||||||
|
@ -105,14 +106,14 @@ def install_environment(
|
||||||
os.mkdir(directory)
|
os.mkdir(directory)
|
||||||
|
|
||||||
|
|
||||||
def get_docker_user() -> Tuple[str, ...]: # pragma: win32 no cover
|
def get_docker_user() -> tuple[str, ...]: # pragma: win32 no cover
|
||||||
try:
|
try:
|
||||||
return ('-u', f'{os.getuid()}:{os.getgid()}')
|
return ('-u', f'{os.getuid()}:{os.getgid()}')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
def docker_cmd() -> Tuple[str, ...]: # pragma: win32 no cover
|
def docker_cmd() -> tuple[str, ...]: # pragma: win32 no cover
|
||||||
return (
|
return (
|
||||||
'docker', 'run',
|
'docker', 'run',
|
||||||
'--rm',
|
'--rm',
|
||||||
|
@ -129,7 +130,7 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]: # pragma: win32 no cover
|
) -> tuple[int, bytes]: # pragma: win32 no cover
|
||||||
# Rebuild the docker image in case it has gone missing, as many people do
|
# Rebuild the docker image in case it has gone missing, as many people do
|
||||||
# automated cleanup of docker images.
|
# automated cleanup of docker images.
|
||||||
build_docker_image(hook.prefix, pull=False)
|
build_docker_image(hook.prefix, pull=False)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import helpers
|
from pre_commit.languages import helpers
|
||||||
|
@ -15,6 +16,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]: # pragma: win32 no cover
|
) -> tuple[int, bytes]: # pragma: win32 no cover
|
||||||
cmd = docker_cmd() + hook.cmd
|
cmd = docker_cmd() + hook.cmd
|
||||||
return helpers.run_xargs(hook, cmd, file_args, color=color)
|
return helpers.run_xargs(hook, cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -84,6 +85,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import helpers
|
from pre_commit.languages import helpers
|
||||||
|
@ -14,7 +15,7 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
out = f'{hook.entry}\n\n'.encode()
|
out = f'{hook.entry}\n\n'.encode()
|
||||||
out += b'\n'.join(f.encode() for f in file_args) + b'\n'
|
out += b'\n'.join(f.encode() for f in file_args) + b'\n'
|
||||||
return 1, out
|
return 1, out
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
|
@ -95,6 +96,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import overload
|
from typing import overload
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
|
@ -32,7 +31,7 @@ def exe_exists(exe: str) -> bool:
|
||||||
|
|
||||||
homedir = os.path.expanduser('~')
|
homedir = os.path.expanduser('~')
|
||||||
try:
|
try:
|
||||||
common: Optional[str] = os.path.commonpath((found, homedir))
|
common: str | None = os.path.commonpath((found, homedir))
|
||||||
except ValueError: # on windows, different drives raises ValueError
|
except ValueError: # on windows, different drives raises ValueError
|
||||||
common = None
|
common = None
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ def exe_exists(exe: str) -> bool:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_setup_cmd(prefix: Prefix, cmd: Tuple[str, ...], **kwargs: Any) -> None:
|
def run_setup_cmd(prefix: Prefix, cmd: tuple[str, ...], **kwargs: Any) -> None:
|
||||||
cmd_output_b(*cmd, cwd=prefix.prefix_dir, **kwargs)
|
cmd_output_b(*cmd, cwd=prefix.prefix_dir, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +57,7 @@ def environment_dir(d: None, language_version: str) -> None: ...
|
||||||
def environment_dir(d: str, language_version: str) -> str: ...
|
def environment_dir(d: str, language_version: str) -> str: ...
|
||||||
|
|
||||||
|
|
||||||
def environment_dir(d: Optional[str], language_version: str) -> Optional[str]:
|
def environment_dir(d: str | None, language_version: str) -> str | None:
|
||||||
if d is None:
|
if d is None:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
|
@ -68,7 +67,8 @@ def environment_dir(d: Optional[str], language_version: str) -> Optional[str]:
|
||||||
def assert_version_default(binary: str, version: str) -> None:
|
def assert_version_default(binary: str, version: str) -> None:
|
||||||
if version != C.DEFAULT:
|
if version != C.DEFAULT:
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
f'For now, pre-commit requires system-installed {binary}',
|
f'for now, pre-commit requires system-installed {binary} -- '
|
||||||
|
f'you selected `language_version: {version}`',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,8 +78,9 @@ def assert_no_additional_deps(
|
||||||
) -> None:
|
) -> None:
|
||||||
if additional_deps:
|
if additional_deps:
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
f'For now, pre-commit does not support '
|
f'for now, pre-commit does not support '
|
||||||
f'additional_dependencies for {lang}',
|
f'additional_dependencies for {lang} -- '
|
||||||
|
f'you selected `additional_dependencies: {additional_deps}`',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ def no_install(
|
||||||
prefix: Prefix,
|
prefix: Prefix,
|
||||||
version: str,
|
version: str,
|
||||||
additional_dependencies: Sequence[str],
|
additional_dependencies: Sequence[str],
|
||||||
) -> 'NoReturn':
|
) -> NoReturn:
|
||||||
raise AssertionError('This type is not installable')
|
raise AssertionError('This type is not installable')
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ def target_concurrency(hook: Hook) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def _shuffled(seq: Sequence[str]) -> List[str]:
|
def _shuffled(seq: Sequence[str]) -> list[str]:
|
||||||
"""Deterministically shuffle"""
|
"""Deterministically shuffle"""
|
||||||
fixed_random = random.Random()
|
fixed_random = random.Random()
|
||||||
fixed_random.seed(FIXED_RANDOM_SEED, version=1)
|
fixed_random.seed(FIXED_RANDOM_SEED, version=1)
|
||||||
|
@ -125,10 +126,10 @@ def _shuffled(seq: Sequence[str]) -> List[str]:
|
||||||
|
|
||||||
def run_xargs(
|
def run_xargs(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
cmd: Tuple[str, ...],
|
cmd: tuple[str, ...],
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
# Shuffle the files so that they more evenly fill out the xargs partitions,
|
# Shuffle the files so that they more evenly fill out the xargs partitions,
|
||||||
# but do it deterministically in case a hook cares about ordering.
|
# but do it deterministically in case a hook cares about ordering.
|
||||||
file_args = _shuffled(file_args)
|
file_args = _shuffled(file_args)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -85,6 +86,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]: # pragma: win32 no cover
|
) -> tuple[int, bytes]: # pragma: win32 no cover
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -122,6 +123,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix, hook.language_version):
|
with in_env(hook.prefix, hook.language_version):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
from pre_commit.envcontext import PatchesT
|
from pre_commit.envcontext import PatchesT
|
||||||
|
@ -62,6 +63,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix, hook.language_version):
|
with in_env(hook.prefix, hook.language_version):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
|
||||||
from typing import Pattern
|
from typing import Pattern
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
|
@ -90,12 +90,12 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
exe = (sys.executable, '-m', __name__) + tuple(hook.args) + (hook.entry,)
|
exe = (sys.executable, '-m', __name__) + tuple(hook.args) + (hook.entry,)
|
||||||
return xargs(exe, file_args, color=color)
|
return xargs(exe, file_args, color=color)
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description=(
|
description=(
|
||||||
'grep-like finder using python regexes. Unlike grep, this tool '
|
'grep-like finder using python regexes. Unlike grep, this tool '
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict
|
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -35,7 +34,7 @@ def _version_info(exe: str) -> str:
|
||||||
return f'<<error retrieving version from {exe}>>'
|
return f'<<error retrieving version from {exe}>>'
|
||||||
|
|
||||||
|
|
||||||
def _read_pyvenv_cfg(filename: str) -> Dict[str, str]:
|
def _read_pyvenv_cfg(filename: str) -> dict[str, str]:
|
||||||
ret = {}
|
ret = {}
|
||||||
with open(filename, encoding='UTF-8') as f:
|
with open(filename, encoding='UTF-8') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
|
@ -65,7 +64,7 @@ def get_env_patch(venv: str) -> PatchesT:
|
||||||
|
|
||||||
def _find_by_py_launcher(
|
def _find_by_py_launcher(
|
||||||
version: str,
|
version: str,
|
||||||
) -> Optional[str]: # pragma: no cover (windows only)
|
) -> str | None: # pragma: no cover (windows only)
|
||||||
if version.startswith('python'):
|
if version.startswith('python'):
|
||||||
num = version[len('python'):]
|
num = version[len('python'):]
|
||||||
cmd = ('py', f'-{num}', '-c', 'import sys; print(sys.executable)')
|
cmd = ('py', f'-{num}', '-c', 'import sys; print(sys.executable)')
|
||||||
|
@ -77,8 +76,8 @@ def _find_by_py_launcher(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _find_by_sys_executable() -> Optional[str]:
|
def _find_by_sys_executable() -> str | None:
|
||||||
def _norm(path: str) -> Optional[str]:
|
def _norm(path: str) -> str | None:
|
||||||
_, exe = os.path.split(path.lower())
|
_, exe = os.path.split(path.lower())
|
||||||
exe, _, _ = exe.partition('.exe')
|
exe, _, _ = exe.partition('.exe')
|
||||||
if exe not in {'python', 'pythonw'} and find_executable(exe):
|
if exe not in {'python', 'pythonw'} and find_executable(exe):
|
||||||
|
@ -133,7 +132,7 @@ def _sys_executable_matches(version: str) -> bool:
|
||||||
return sys.version_info[:len(info)] == info
|
return sys.version_info[:len(info)] == info
|
||||||
|
|
||||||
|
|
||||||
def norm_version(version: str) -> Optional[str]:
|
def norm_version(version: str) -> str | None:
|
||||||
if version == C.DEFAULT: # use virtualenv's default
|
if version == C.DEFAULT: # use virtualenv's default
|
||||||
return None
|
return None
|
||||||
elif _sys_executable_matches(version): # virtualenv defaults to our exe
|
elif _sys_executable_matches(version): # virtualenv defaults to our exe
|
||||||
|
@ -209,6 +208,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix, hook.language_version):
|
with in_env(hook.prefix, hook.language_version):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
from pre_commit.envcontext import PatchesT
|
from pre_commit.envcontext import PatchesT
|
||||||
|
@ -58,7 +59,11 @@ def _prefix_if_non_local_file_entry(
|
||||||
|
|
||||||
|
|
||||||
def _rscript_exec() -> str:
|
def _rscript_exec() -> str:
|
||||||
return os.path.join(os.getenv('R_HOME', ''), 'Rscript')
|
r_home = os.environ.get('R_HOME')
|
||||||
|
if r_home is None:
|
||||||
|
return 'Rscript'
|
||||||
|
else:
|
||||||
|
return os.path.join(r_home, 'bin', 'Rscript')
|
||||||
|
|
||||||
|
|
||||||
def _entry_validate(entry: Sequence[str]) -> None:
|
def _entry_validate(entry: Sequence[str]) -> None:
|
||||||
|
@ -80,7 +85,7 @@ def _entry_validate(entry: Sequence[str]) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _cmd_from_hook(hook: Hook) -> Tuple[str, ...]:
|
def _cmd_from_hook(hook: Hook) -> tuple[str, ...]:
|
||||||
entry = shlex.split(hook.entry)
|
entry = shlex.split(hook.entry)
|
||||||
_entry_validate(entry)
|
_entry_validate(entry)
|
||||||
|
|
||||||
|
@ -102,9 +107,7 @@ def install_environment(
|
||||||
shutil.copy(prefix.path('renv.lock'), env_dir)
|
shutil.copy(prefix.path('renv.lock'), env_dir)
|
||||||
shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv'))
|
shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv'))
|
||||||
|
|
||||||
cmd_output_b(
|
r_code_inst_environment = f"""\
|
||||||
_rscript_exec(), '--vanilla', '-e',
|
|
||||||
f"""\
|
|
||||||
prefix_dir <- {prefix.prefix_dir!r}
|
prefix_dir <- {prefix.prefix_dir!r}
|
||||||
options(
|
options(
|
||||||
repos = c(CRAN = "https://cran.rstudio.com"),
|
repos = c(CRAN = "https://cran.rstudio.com"),
|
||||||
|
@ -131,24 +134,41 @@ def install_environment(
|
||||||
if (is_package) {{
|
if (is_package) {{
|
||||||
renv::install(prefix_dir)
|
renv::install(prefix_dir)
|
||||||
}}
|
}}
|
||||||
""",
|
"""
|
||||||
|
|
||||||
|
cmd_output_b(
|
||||||
|
_rscript_exec(), '--vanilla', '-e',
|
||||||
|
_inline_r_setup(r_code_inst_environment),
|
||||||
cwd=env_dir,
|
cwd=env_dir,
|
||||||
)
|
)
|
||||||
if additional_dependencies:
|
if additional_dependencies:
|
||||||
|
r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))'
|
||||||
with in_env(prefix, version):
|
with in_env(prefix, version):
|
||||||
cmd_output_b(
|
cmd_output_b(
|
||||||
_rscript_exec(), *RSCRIPT_OPTS, '-e',
|
_rscript_exec(), *RSCRIPT_OPTS, '-e',
|
||||||
'renv::install(commandArgs(trailingOnly = TRUE))',
|
_inline_r_setup(r_code_inst_add),
|
||||||
*additional_dependencies,
|
*additional_dependencies,
|
||||||
cwd=env_dir,
|
cwd=env_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _inline_r_setup(code: str) -> str:
|
||||||
|
"""
|
||||||
|
Some behaviour of R cannot be configured via env variables, but can
|
||||||
|
only be configured via R options once R has started. These are set here.
|
||||||
|
"""
|
||||||
|
with_option = f"""\
|
||||||
|
options(install.packages.compile.from.source = "never")
|
||||||
|
{code}
|
||||||
|
"""
|
||||||
|
return with_option
|
||||||
|
|
||||||
|
|
||||||
def run_hook(
|
def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix, hook.language_version):
|
with in_env(hook.prefix, hook.language_version):
|
||||||
return helpers.run_xargs(
|
return helpers.run_xargs(
|
||||||
hook, _cmd_from_hook(hook), file_args, color=color,
|
hook, _cmd_from_hook(hook), file_args, color=color,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -5,7 +7,6 @@ import shutil
|
||||||
import tarfile
|
import tarfile
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -146,6 +147,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix, hook.language_version):
|
with in_env(hook.prefix, hook.language_version):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ def in_env(prefix: Prefix) -> Generator[None, None, None]:
|
||||||
|
|
||||||
def _add_dependencies(
|
def _add_dependencies(
|
||||||
cargo_toml_path: str,
|
cargo_toml_path: str,
|
||||||
additional_dependencies: Set[str],
|
additional_dependencies: set[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
with open(cargo_toml_path, 'r+') as f:
|
with open(cargo_toml_path, 'r+') as f:
|
||||||
cargo_toml = toml.load(f)
|
cargo_toml = toml.load(f)
|
||||||
|
@ -81,7 +81,7 @@ def install_environment(
|
||||||
_add_dependencies(prefix.path('Cargo.toml'), lib_deps)
|
_add_dependencies(prefix.path('Cargo.toml'), lib_deps)
|
||||||
|
|
||||||
with clean_path_on_failure(directory):
|
with clean_path_on_failure(directory):
|
||||||
packages_to_install: Set[Tuple[str, ...]] = {('--path', '.')}
|
packages_to_install: set[tuple[str, ...]] = {('--path', '.')}
|
||||||
for cli_dep in cli_deps:
|
for cli_dep in cli_deps:
|
||||||
cli_dep = cli_dep[len('cli:'):]
|
cli_dep = cli_dep[len('cli:'):]
|
||||||
package, _, version = cli_dep.partition(':')
|
package, _, version = cli_dep.partition(':')
|
||||||
|
@ -101,6 +101,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import helpers
|
from pre_commit.languages import helpers
|
||||||
|
@ -14,6 +15,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
cmd = (hook.prefix.path(hook.cmd[0]), *hook.cmd[1:])
|
cmd = (hook.prefix.path(hook.cmd[0]), *hook.cmd[1:])
|
||||||
return helpers.run_xargs(hook, cmd, file_args, color=color)
|
return helpers.run_xargs(hook, cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
|
@ -59,6 +60,6 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]: # pragma: win32 no cover
|
) -> tuple[int, bytes]: # pragma: win32 no cover
|
||||||
with in_env(hook.prefix):
|
with in_env(hook.prefix):
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import helpers
|
from pre_commit.languages import helpers
|
||||||
|
@ -15,5 +16,5 @@ def run_hook(
|
||||||
hook: Hook,
|
hook: Hook,
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
|
@ -46,34 +45,10 @@ def _add_config_option(parser: argparse.ArgumentParser) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AppendReplaceDefault(argparse.Action):
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.appended = False
|
|
||||||
|
|
||||||
def __call__(
|
|
||||||
self,
|
|
||||||
parser: argparse.ArgumentParser,
|
|
||||||
namespace: argparse.Namespace,
|
|
||||||
values: Union[str, Sequence[str], None],
|
|
||||||
option_string: Optional[str] = None,
|
|
||||||
) -> None:
|
|
||||||
if not self.appended:
|
|
||||||
setattr(namespace, self.dest, [])
|
|
||||||
self.appended = True
|
|
||||||
getattr(namespace, self.dest).append(values)
|
|
||||||
|
|
||||||
|
|
||||||
def _add_hook_type_option(parser: argparse.ArgumentParser) -> None:
|
def _add_hook_type_option(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-t', '--hook-type', choices=(
|
'-t', '--hook-type',
|
||||||
'pre-commit', 'pre-merge-commit', 'pre-push', 'prepare-commit-msg',
|
choices=C.HOOK_TYPES, action='append', dest='hook_types',
|
||||||
'commit-msg', 'post-commit', 'post-checkout', 'post-merge',
|
|
||||||
'post-rewrite',
|
|
||||||
),
|
|
||||||
action=AppendReplaceDefault,
|
|
||||||
default=['pre-commit'],
|
|
||||||
dest='hook_types',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,7 +81,7 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--from-ref', '--source', '-s',
|
'--from-ref', '--source', '-s',
|
||||||
help=(
|
help=(
|
||||||
'(for usage with `--from-ref`) -- this option represents the '
|
'(for usage with `--to-ref`) -- this option represents the '
|
||||||
'original ref in a `from_ref...to_ref` diff expression. '
|
'original ref in a `from_ref...to_ref` diff expression. '
|
||||||
'For `pre-push` hooks, this represents the branch you are pushing '
|
'For `pre-push` hooks, this represents the branch you are pushing '
|
||||||
'to. '
|
'to. '
|
||||||
|
@ -117,7 +92,7 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--to-ref', '--origin', '-o',
|
'--to-ref', '--origin', '-o',
|
||||||
help=(
|
help=(
|
||||||
'(for usage with `--to-ref`) -- this option represents the '
|
'(for usage with `--from-ref`) -- this option represents the '
|
||||||
'destination ref in a `from_ref...to_ref` diff expression. '
|
'destination ref in a `from_ref...to_ref` diff expression. '
|
||||||
'For `pre-push` hooks, this represents the branch being pushed. '
|
'For `pre-push` hooks, this represents the branch being pushed. '
|
||||||
'For `post-checkout` hooks, this represents the branch that is '
|
'For `post-checkout` hooks, this represents the branch that is '
|
||||||
|
@ -175,7 +150,7 @@ def _adjust_args_and_chdir(args: argparse.Namespace) -> None:
|
||||||
args.repo = os.path.relpath(args.repo)
|
args.repo = os.path.relpath(args.repo)
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
argv = argv if argv is not None else sys.argv[1:]
|
argv = argv if argv is not None else sys.argv[1:]
|
||||||
parser = argparse.ArgumentParser(prog='pre-commit')
|
parser = argparse.ArgumentParser(prog='pre-commit')
|
||||||
|
|
||||||
|
@ -197,7 +172,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
||||||
autoupdate_parser.add_argument(
|
autoupdate_parser.add_argument(
|
||||||
'--bleeding-edge', action='store_true',
|
'--bleeding-edge', action='store_true',
|
||||||
help=(
|
help=(
|
||||||
'Update to the bleeding edge of `master` instead of the latest '
|
'Update to the bleeding edge of `HEAD` instead of the latest '
|
||||||
'tagged version (the default behavior).'
|
'tagged version (the default behavior).'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -399,7 +374,10 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
||||||
elif args.command == 'try-repo':
|
elif args.command == 'try-repo':
|
||||||
return try_repo(args)
|
return try_repo(args)
|
||||||
elif args.command == 'uninstall':
|
elif args.command == 'uninstall':
|
||||||
return uninstall(hook_types=args.hook_types)
|
return uninstall(
|
||||||
|
config_file=args.config,
|
||||||
|
hook_types=args.hook_types,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f'Command {args.command} not implemented.',
|
f'Command {args.command} not implemented.',
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
|
@ -27,7 +28,7 @@ def check_all_hooks_match_files(config_file: str) -> int:
|
||||||
return retv
|
return retv
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE])
|
parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE])
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
from cfgv import apply_defaults
|
from cfgv import apply_defaults
|
||||||
|
@ -65,7 +66,7 @@ def check_useless_excludes(config_file: str) -> int:
|
||||||
return retv
|
return retv
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE])
|
parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE])
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
argv = argv if argv is not None else sys.argv[1:]
|
argv = argv if argv is not None else sys.argv[1:]
|
||||||
for arg in argv:
|
for arg in argv:
|
||||||
output.write_line(arg)
|
output.write_line(arg)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None:
|
def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None:
|
||||||
|
@ -11,9 +12,9 @@ def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None:
|
||||||
|
|
||||||
|
|
||||||
def write_line_b(
|
def write_line_b(
|
||||||
s: Optional[bytes] = None,
|
s: bytes | None = None,
|
||||||
stream: IO[bytes] = sys.stdout.buffer,
|
stream: IO[bytes] = sys.stdout.buffer,
|
||||||
logfile_name: Optional[str] = None,
|
logfile_name: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
with contextlib.ExitStack() as exit_stack:
|
with contextlib.ExitStack() as exit_stack:
|
||||||
output_streams = [stream]
|
output_streams = [stream]
|
||||||
|
@ -28,5 +29,5 @@ def write_line_b(
|
||||||
output_stream.flush()
|
output_stream.flush()
|
||||||
|
|
||||||
|
|
||||||
def write_line(s: Optional[str] = None, **kwargs: Any) -> None:
|
def write_line(s: str | None = None, **kwargs: Any) -> None:
|
||||||
write_line_b(s.encode() if s is not None else s, **kwargs)
|
write_line_b(s.encode() if s is not None else s, **kwargs)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from identify.identify import parse_shebang_from_file
|
from identify.identify import parse_shebang_from_file
|
||||||
|
@ -11,11 +11,11 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class ExecutableNotFoundError(OSError):
|
class ExecutableNotFoundError(OSError):
|
||||||
def to_output(self) -> Tuple[int, bytes, None]:
|
def to_output(self) -> tuple[int, bytes, None]:
|
||||||
return (1, self.args[0].encode(), None)
|
return (1, self.args[0].encode(), None)
|
||||||
|
|
||||||
|
|
||||||
def parse_filename(filename: str) -> Tuple[str, ...]:
|
def parse_filename(filename: str) -> tuple[str, ...]:
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
return ()
|
return ()
|
||||||
else:
|
else:
|
||||||
|
@ -23,8 +23,8 @@ def parse_filename(filename: str) -> Tuple[str, ...]:
|
||||||
|
|
||||||
|
|
||||||
def find_executable(
|
def find_executable(
|
||||||
exe: str, _environ: Optional[Mapping[str, str]] = None,
|
exe: str, _environ: Mapping[str, str] | None = None,
|
||||||
) -> Optional[str]:
|
) -> str | None:
|
||||||
exe = os.path.normpath(exe)
|
exe = os.path.normpath(exe)
|
||||||
if os.sep in exe:
|
if os.sep in exe:
|
||||||
return exe
|
return exe
|
||||||
|
@ -47,7 +47,7 @@ def find_executable(
|
||||||
|
|
||||||
|
|
||||||
def normexe(orig: str) -> str:
|
def normexe(orig: str) -> str:
|
||||||
def _error(msg: str) -> 'NoReturn':
|
def _error(msg: str) -> NoReturn:
|
||||||
raise ExecutableNotFoundError(f'Executable `{orig}` {msg}')
|
raise ExecutableNotFoundError(f'Executable `{orig}` {msg}')
|
||||||
|
|
||||||
if os.sep not in orig and (not os.altsep or os.altsep not in orig):
|
if os.sep not in orig and (not os.altsep or os.altsep not in orig):
|
||||||
|
@ -65,7 +65,7 @@ def normexe(orig: str) -> str:
|
||||||
return orig
|
return orig
|
||||||
|
|
||||||
|
|
||||||
def normalize_cmd(cmd: Tuple[str, ...]) -> Tuple[str, ...]:
|
def normalize_cmd(cmd: tuple[str, ...]) -> tuple[str, ...]:
|
||||||
"""Fixes for the following issues on windows
|
"""Fixes for the following issues on windows
|
||||||
- https://bugs.python.org/issue8557
|
- https://bugs.python.org/issue8557
|
||||||
- windows does not parse shebangs
|
- windows does not parse shebangs
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
|
|
||||||
class Prefix(NamedTuple):
|
class Prefix(NamedTuple):
|
||||||
|
@ -12,6 +13,6 @@ class Prefix(NamedTuple):
|
||||||
def exists(self, *parts: str) -> bool:
|
def exists(self, *parts: str) -> bool:
|
||||||
return os.path.exists(self.path(*parts))
|
return os.path.exists(self.path(*parts))
|
||||||
|
|
||||||
def star(self, end: str) -> Tuple[str, ...]:
|
def star(self, end: str) -> tuple[str, ...]:
|
||||||
paths = os.listdir(self.prefix_dir)
|
paths = os.listdir(self.prefix_dir)
|
||||||
return tuple(path for path in paths if path.endswith(end))
|
return tuple(path for path in paths if path.endswith(end))
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.clientlib import load_manifest
|
from pre_commit.clientlib import load_manifest
|
||||||
|
@ -33,7 +30,7 @@ def _state_filename(prefix: Prefix, venv: str) -> str:
|
||||||
return prefix.path(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}')
|
return prefix.path(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}')
|
||||||
|
|
||||||
|
|
||||||
def _read_state(prefix: Prefix, venv: str) -> Optional[object]:
|
def _read_state(prefix: Prefix, venv: str) -> object | None:
|
||||||
filename = _state_filename(prefix, venv)
|
filename = _state_filename(prefix, venv)
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
return None
|
return None
|
||||||
|
@ -93,9 +90,9 @@ def _hook_install(hook: Hook) -> None:
|
||||||
|
|
||||||
|
|
||||||
def _hook(
|
def _hook(
|
||||||
*hook_dicts: Dict[str, Any],
|
*hook_dicts: dict[str, Any],
|
||||||
root_config: Dict[str, Any],
|
root_config: dict[str, Any],
|
||||||
) -> Dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
ret, rest = dict(hook_dicts[0]), hook_dicts[1:]
|
ret, rest = dict(hook_dicts[0]), hook_dicts[1:]
|
||||||
for dct in rest:
|
for dct in rest:
|
||||||
ret.update(dct)
|
ret.update(dct)
|
||||||
|
@ -140,10 +137,10 @@ def _hook(
|
||||||
|
|
||||||
|
|
||||||
def _non_cloned_repository_hooks(
|
def _non_cloned_repository_hooks(
|
||||||
repo_config: Dict[str, Any],
|
repo_config: dict[str, Any],
|
||||||
store: Store,
|
store: Store,
|
||||||
root_config: Dict[str, Any],
|
root_config: dict[str, Any],
|
||||||
) -> Tuple[Hook, ...]:
|
) -> tuple[Hook, ...]:
|
||||||
def _prefix(language_name: str, deps: Sequence[str]) -> Prefix:
|
def _prefix(language_name: str, deps: Sequence[str]) -> Prefix:
|
||||||
language = languages[language_name]
|
language = languages[language_name]
|
||||||
# pygrep / script / system / docker_image do not have
|
# pygrep / script / system / docker_image do not have
|
||||||
|
@ -164,10 +161,10 @@ def _non_cloned_repository_hooks(
|
||||||
|
|
||||||
|
|
||||||
def _cloned_repository_hooks(
|
def _cloned_repository_hooks(
|
||||||
repo_config: Dict[str, Any],
|
repo_config: dict[str, Any],
|
||||||
store: Store,
|
store: Store,
|
||||||
root_config: Dict[str, Any],
|
root_config: dict[str, Any],
|
||||||
) -> Tuple[Hook, ...]:
|
) -> tuple[Hook, ...]:
|
||||||
repo, rev = repo_config['repo'], repo_config['rev']
|
repo, rev = repo_config['repo'], repo_config['rev']
|
||||||
manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE)
|
manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE)
|
||||||
by_id = {hook['id']: hook for hook in load_manifest(manifest_path)}
|
by_id = {hook['id']: hook for hook in load_manifest(manifest_path)}
|
||||||
|
@ -196,10 +193,10 @@ def _cloned_repository_hooks(
|
||||||
|
|
||||||
|
|
||||||
def _repository_hooks(
|
def _repository_hooks(
|
||||||
repo_config: Dict[str, Any],
|
repo_config: dict[str, Any],
|
||||||
store: Store,
|
store: Store,
|
||||||
root_config: Dict[str, Any],
|
root_config: dict[str, Any],
|
||||||
) -> Tuple[Hook, ...]:
|
) -> tuple[Hook, ...]:
|
||||||
if repo_config['repo'] in {LOCAL, META}:
|
if repo_config['repo'] in {LOCAL, META}:
|
||||||
return _non_cloned_repository_hooks(repo_config, store, root_config)
|
return _non_cloned_repository_hooks(repo_config, store, root_config)
|
||||||
else:
|
else:
|
||||||
|
@ -207,8 +204,8 @@ def _repository_hooks(
|
||||||
|
|
||||||
|
|
||||||
def install_hook_envs(hooks: Sequence[Hook], store: Store) -> None:
|
def install_hook_envs(hooks: Sequence[Hook], store: Store) -> None:
|
||||||
def _need_installed() -> List[Hook]:
|
def _need_installed() -> list[Hook]:
|
||||||
seen: Set[Tuple[Prefix, str, str, Tuple[str, ...]]] = set()
|
seen: set[tuple[Prefix, str, str, tuple[str, ...]]] = set()
|
||||||
ret = []
|
ret = []
|
||||||
for hook in hooks:
|
for hook in hooks:
|
||||||
if hook.install_key not in seen and not _hook_installed(hook):
|
if hook.install_key not in seen and not _hook_installed(hook):
|
||||||
|
@ -224,7 +221,7 @@ def install_hook_envs(hooks: Sequence[Hook], store: Store) -> None:
|
||||||
_hook_install(hook)
|
_hook_install(hook)
|
||||||
|
|
||||||
|
|
||||||
def all_hooks(root_config: Dict[str, Any], store: Store) -> Tuple[Hook, ...]:
|
def all_hooks(root_config: dict[str, Any], store: Store) -> tuple[Hook, ...]:
|
||||||
return tuple(
|
return tuple(
|
||||||
hook
|
hook
|
||||||
for repo in root_config['repos']
|
for repo in root_config['repos']
|
||||||
|
|
Binary file not shown.
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -64,9 +66,9 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
|
||||||
|
|
||||||
# prevent recursive post-checkout hooks (#1418)
|
# prevent recursive post-checkout hooks (#1418)
|
||||||
no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1')
|
no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1')
|
||||||
cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env)
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
# Try to apply the patch we saved
|
# Try to apply the patch we saved
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -5,10 +7,7 @@ import sqlite3
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import file_lock
|
from pre_commit import file_lock
|
||||||
|
@ -40,7 +39,7 @@ def _get_default_directory() -> str:
|
||||||
class Store:
|
class Store:
|
||||||
get_default_directory = staticmethod(_get_default_directory)
|
get_default_directory = staticmethod(_get_default_directory)
|
||||||
|
|
||||||
def __init__(self, directory: Optional[str] = None) -> None:
|
def __init__(self, directory: str | None = None) -> None:
|
||||||
self.directory = directory or Store.get_default_directory()
|
self.directory = directory or Store.get_default_directory()
|
||||||
self.db_path = os.path.join(self.directory, 'db.db')
|
self.db_path = os.path.join(self.directory, 'db.db')
|
||||||
self.readonly = (
|
self.readonly = (
|
||||||
|
@ -92,7 +91,7 @@ class Store:
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def connect(
|
def connect(
|
||||||
self,
|
self,
|
||||||
db_path: Optional[str] = None,
|
db_path: str | None = None,
|
||||||
) -> Generator[sqlite3.Connection, None, None]:
|
) -> Generator[sqlite3.Connection, None, None]:
|
||||||
db_path = db_path or self.db_path
|
db_path = db_path or self.db_path
|
||||||
# sqlite doesn't close its fd with its contextmanager >.<
|
# sqlite doesn't close its fd with its contextmanager >.<
|
||||||
|
@ -119,7 +118,7 @@ class Store:
|
||||||
) -> str:
|
) -> str:
|
||||||
repo = self.db_repo_name(repo, deps)
|
repo = self.db_repo_name(repo, deps)
|
||||||
|
|
||||||
def _get_result() -> Optional[str]:
|
def _get_result() -> str | None:
|
||||||
# Check if we already exist
|
# Check if we already exist
|
||||||
with self.connect() as db:
|
with self.connect() as db:
|
||||||
result = db.execute(
|
result = db.execute(
|
||||||
|
@ -239,18 +238,18 @@ class Store:
|
||||||
self._create_config_table(db)
|
self._create_config_table(db)
|
||||||
db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))
|
db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))
|
||||||
|
|
||||||
def select_all_configs(self) -> List[str]:
|
def select_all_configs(self) -> list[str]:
|
||||||
with self.connect() as db:
|
with self.connect() as db:
|
||||||
self._create_config_table(db)
|
self._create_config_table(db)
|
||||||
rows = db.execute('SELECT path FROM configs').fetchall()
|
rows = db.execute('SELECT path FROM configs').fetchall()
|
||||||
return [path for path, in rows]
|
return [path for path, in rows]
|
||||||
|
|
||||||
def delete_configs(self, configs: List[str]) -> None:
|
def delete_configs(self, configs: list[str]) -> None:
|
||||||
with self.connect() as db:
|
with self.connect() as db:
|
||||||
rows = [(path,) for path in configs]
|
rows = [(path,) for path in configs]
|
||||||
db.executemany('DELETE FROM configs WHERE path = ?', rows)
|
db.executemany('DELETE FROM configs WHERE path = ?', rows)
|
||||||
|
|
||||||
def select_all_repos(self) -> List[Tuple[str, str, str]]:
|
def select_all_repos(self) -> list[tuple[str, str, str]]:
|
||||||
with self.connect() as db:
|
with self.connect() as db:
|
||||||
return db.execute('SELECT repo, ref, path from repos').fetchall()
|
return db.execute('SELECT repo, ref, path from repos').fetchall()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import functools
|
import functools
|
||||||
|
import importlib.resources
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
|
@ -10,24 +13,13 @@ import tempfile
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Optional
|
|
||||||
from typing import Tuple
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from pre_commit import parse_shebang
|
from pre_commit import parse_shebang
|
||||||
|
|
||||||
if sys.version_info >= (3, 7): # pragma: >=3.7 cover
|
|
||||||
from importlib.resources import open_binary
|
|
||||||
from importlib.resources import read_text
|
|
||||||
else: # pragma: <3.7 cover
|
|
||||||
from importlib_resources import open_binary
|
|
||||||
from importlib_resources import read_text
|
|
||||||
|
|
||||||
Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
|
Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
|
||||||
yaml_load = functools.partial(yaml.load, Loader=Loader)
|
yaml_load = functools.partial(yaml.load, Loader=Loader)
|
||||||
Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper)
|
Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper)
|
||||||
|
@ -73,11 +65,11 @@ def tmpdir() -> Generator[str, None, None]:
|
||||||
|
|
||||||
|
|
||||||
def resource_bytesio(filename: str) -> IO[bytes]:
|
def resource_bytesio(filename: str) -> IO[bytes]:
|
||||||
return open_binary('pre_commit.resources', filename)
|
return importlib.resources.open_binary('pre_commit.resources', filename)
|
||||||
|
|
||||||
|
|
||||||
def resource_text(filename: str) -> str:
|
def resource_text(filename: str) -> str:
|
||||||
return read_text('pre_commit.resources', filename)
|
return importlib.resources.read_text('pre_commit.resources', filename)
|
||||||
|
|
||||||
|
|
||||||
def make_executable(filename: str) -> None:
|
def make_executable(filename: str) -> None:
|
||||||
|
@ -90,10 +82,10 @@ class CalledProcessError(RuntimeError):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
returncode: int,
|
returncode: int,
|
||||||
cmd: Tuple[str, ...],
|
cmd: tuple[str, ...],
|
||||||
expected_returncode: int,
|
expected_returncode: int,
|
||||||
stdout: bytes,
|
stdout: bytes,
|
||||||
stderr: Optional[bytes],
|
stderr: bytes | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(returncode, cmd, expected_returncode, stdout, stderr)
|
super().__init__(returncode, cmd, expected_returncode, stdout, stderr)
|
||||||
self.returncode = returncode
|
self.returncode = returncode
|
||||||
|
@ -103,7 +95,7 @@ class CalledProcessError(RuntimeError):
|
||||||
self.stderr = stderr
|
self.stderr = stderr
|
||||||
|
|
||||||
def __bytes__(self) -> bytes:
|
def __bytes__(self) -> bytes:
|
||||||
def _indent_or_none(part: Optional[bytes]) -> bytes:
|
def _indent_or_none(part: bytes | None) -> bytes:
|
||||||
if part:
|
if part:
|
||||||
return b'\n ' + part.replace(b'\n', b'\n ')
|
return b'\n ' + part.replace(b'\n', b'\n ')
|
||||||
else:
|
else:
|
||||||
|
@ -121,20 +113,20 @@ class CalledProcessError(RuntimeError):
|
||||||
return self.__bytes__().decode()
|
return self.__bytes__().decode()
|
||||||
|
|
||||||
|
|
||||||
def _setdefault_kwargs(kwargs: Dict[str, Any]) -> None:
|
def _setdefault_kwargs(kwargs: dict[str, Any]) -> None:
|
||||||
for arg in ('stdin', 'stdout', 'stderr'):
|
for arg in ('stdin', 'stdout', 'stderr'):
|
||||||
kwargs.setdefault(arg, subprocess.PIPE)
|
kwargs.setdefault(arg, subprocess.PIPE)
|
||||||
|
|
||||||
|
|
||||||
def _oserror_to_output(e: OSError) -> Tuple[int, bytes, None]:
|
def _oserror_to_output(e: OSError) -> tuple[int, bytes, None]:
|
||||||
return 1, force_bytes(e).rstrip(b'\n') + b'\n', None
|
return 1, force_bytes(e).rstrip(b'\n') + b'\n', None
|
||||||
|
|
||||||
|
|
||||||
def cmd_output_b(
|
def cmd_output_b(
|
||||||
*cmd: str,
|
*cmd: str,
|
||||||
retcode: Optional[int] = 0,
|
retcode: int | None = 0,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Tuple[int, bytes, Optional[bytes]]:
|
) -> tuple[int, bytes, bytes | None]:
|
||||||
_setdefault_kwargs(kwargs)
|
_setdefault_kwargs(kwargs)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -156,7 +148,7 @@ def cmd_output_b(
|
||||||
return returncode, stdout_b, stderr_b
|
return returncode, stdout_b, stderr_b
|
||||||
|
|
||||||
|
|
||||||
def cmd_output(*cmd: str, **kwargs: Any) -> Tuple[int, str, Optional[str]]:
|
def cmd_output(*cmd: str, **kwargs: Any) -> tuple[int, str, str | None]:
|
||||||
returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs)
|
returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs)
|
||||||
stdout = stdout_b.decode() if stdout_b is not None else None
|
stdout = stdout_b.decode() if stdout_b is not None else None
|
||||||
stderr = stderr_b.decode() if stderr_b is not None else None
|
stderr = stderr_b.decode() if stderr_b is not None else None
|
||||||
|
@ -169,10 +161,10 @@ if os.name != 'nt': # pragma: win32 no cover
|
||||||
|
|
||||||
class Pty:
|
class Pty:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.r: Optional[int] = None
|
self.r: int | None = None
|
||||||
self.w: Optional[int] = None
|
self.w: int | None = None
|
||||||
|
|
||||||
def __enter__(self) -> 'Pty':
|
def __enter__(self) -> Pty:
|
||||||
self.r, self.w = openpty()
|
self.r, self.w = openpty()
|
||||||
|
|
||||||
# tty flags normally change \n to \r\n
|
# tty flags normally change \n to \r\n
|
||||||
|
@ -195,18 +187,18 @@ if os.name != 'nt': # pragma: win32 no cover
|
||||||
|
|
||||||
def __exit__(
|
def __exit__(
|
||||||
self,
|
self,
|
||||||
exc_type: Optional[Type[BaseException]],
|
exc_type: type[BaseException] | None,
|
||||||
exc_value: Optional[BaseException],
|
exc_value: BaseException | None,
|
||||||
traceback: Optional[TracebackType],
|
traceback: TracebackType | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.close_w()
|
self.close_w()
|
||||||
self.close_r()
|
self.close_r()
|
||||||
|
|
||||||
def cmd_output_p(
|
def cmd_output_p(
|
||||||
*cmd: str,
|
*cmd: str,
|
||||||
retcode: Optional[int] = 0,
|
retcode: int | None = 0,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Tuple[int, bytes, Optional[bytes]]:
|
) -> tuple[int, bytes, bytes | None]:
|
||||||
assert retcode is None
|
assert retcode is None
|
||||||
assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']
|
assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']
|
||||||
_setdefault_kwargs(kwargs)
|
_setdefault_kwargs(kwargs)
|
||||||
|
@ -250,7 +242,7 @@ def rmtree(path: str) -> None:
|
||||||
def handle_remove_readonly(
|
def handle_remove_readonly(
|
||||||
func: Callable[..., Any],
|
func: Callable[..., Any],
|
||||||
path: str,
|
path: str,
|
||||||
exc: Tuple[Type[OSError], OSError, TracebackType],
|
exc: tuple[type[OSError], OSError, TracebackType],
|
||||||
) -> None:
|
) -> None:
|
||||||
excvalue = exc[1]
|
excvalue = exc[1]
|
||||||
if (
|
if (
|
||||||
|
@ -265,7 +257,7 @@ def rmtree(path: str) -> None:
|
||||||
shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)
|
shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)
|
||||||
|
|
||||||
|
|
||||||
def parse_version(s: str) -> Tuple[int, ...]:
|
def parse_version(s: str) -> tuple[int, ...]:
|
||||||
"""poor man's version comparison"""
|
"""poor man's version comparison"""
|
||||||
return tuple(int(p) for p in s.split('.'))
|
return tuple(int(p) for p in s.split('.'))
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import contextlib
|
import contextlib
|
||||||
import math
|
import math
|
||||||
|
@ -8,11 +10,8 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import List
|
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from pre_commit import parse_shebang
|
from pre_commit import parse_shebang
|
||||||
|
@ -23,7 +22,7 @@ TArg = TypeVar('TArg')
|
||||||
TRet = TypeVar('TRet')
|
TRet = TypeVar('TRet')
|
||||||
|
|
||||||
|
|
||||||
def _environ_size(_env: Optional[MutableMapping[str, str]] = None) -> int:
|
def _environ_size(_env: MutableMapping[str, str] | None = None) -> int:
|
||||||
environ = _env if _env is not None else getattr(os, 'environb', os.environ)
|
environ = _env if _env is not None else getattr(os, 'environb', os.environ)
|
||||||
size = 8 * len(environ) # number of pointers in `envp`
|
size = 8 * len(environ) # number of pointers in `envp`
|
||||||
for k, v in environ.items():
|
for k, v in environ.items():
|
||||||
|
@ -62,8 +61,8 @@ def partition(
|
||||||
cmd: Sequence[str],
|
cmd: Sequence[str],
|
||||||
varargs: Sequence[str],
|
varargs: Sequence[str],
|
||||||
target_concurrency: int,
|
target_concurrency: int,
|
||||||
_max_length: Optional[int] = None,
|
_max_length: int | None = None,
|
||||||
) -> Tuple[Tuple[str, ...], ...]:
|
) -> tuple[tuple[str, ...], ...]:
|
||||||
_max_length = _max_length or _get_platform_max_length()
|
_max_length = _max_length or _get_platform_max_length()
|
||||||
|
|
||||||
# Generally, we try to partition evenly into at least `target_concurrency`
|
# Generally, we try to partition evenly into at least `target_concurrency`
|
||||||
|
@ -73,7 +72,7 @@ def partition(
|
||||||
cmd = tuple(cmd)
|
cmd = tuple(cmd)
|
||||||
ret = []
|
ret = []
|
||||||
|
|
||||||
ret_cmd: List[str] = []
|
ret_cmd: list[str] = []
|
||||||
# Reversed so arguments are in order
|
# Reversed so arguments are in order
|
||||||
varargs = list(reversed(varargs))
|
varargs = list(reversed(varargs))
|
||||||
|
|
||||||
|
@ -115,14 +114,14 @@ def _thread_mapper(maxsize: int) -> Generator[
|
||||||
|
|
||||||
|
|
||||||
def xargs(
|
def xargs(
|
||||||
cmd: Tuple[str, ...],
|
cmd: tuple[str, ...],
|
||||||
varargs: Sequence[str],
|
varargs: Sequence[str],
|
||||||
*,
|
*,
|
||||||
color: bool = False,
|
color: bool = False,
|
||||||
target_concurrency: int = 1,
|
target_concurrency: int = 1,
|
||||||
_max_length: int = _get_platform_max_length(),
|
_max_length: int = _get_platform_max_length(),
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Tuple[int, bytes]:
|
) -> tuple[int, bytes]:
|
||||||
"""A simplified implementation of xargs.
|
"""A simplified implementation of xargs.
|
||||||
|
|
||||||
color: Make a pty if on a platform that supports it
|
color: Make a pty if on a platform that supports it
|
||||||
|
@ -152,8 +151,8 @@ def xargs(
|
||||||
partitions = partition(cmd, varargs, target_concurrency, _max_length)
|
partitions = partition(cmd, varargs, target_concurrency, _max_length)
|
||||||
|
|
||||||
def run_cmd_partition(
|
def run_cmd_partition(
|
||||||
run_cmd: Tuple[str, ...],
|
run_cmd: tuple[str, ...],
|
||||||
) -> Tuple[int, bytes, Optional[bytes]]:
|
) -> tuple[int, bytes, bytes | None]:
|
||||||
return cmd_fn(
|
return cmd_fn(
|
||||||
*run_cmd, retcode=None, stderr=subprocess.STDOUT, **kwargs,
|
*run_cmd, retcode=None, stderr=subprocess.STDOUT, **kwargs,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
name = pre_commit
|
name = pre_commit
|
||||||
version = 2.17.0
|
version = 2.18.1
|
||||||
description = A framework for managing and maintaining multi-language pre-commit hooks.
|
description = A framework for managing and maintaining multi-language pre-commit hooks.
|
||||||
long_description = file: README.md
|
long_description = file: README.md
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
|
@ -13,7 +13,6 @@ classifiers =
|
||||||
License :: OSI Approved :: MIT License
|
License :: OSI Approved :: MIT License
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3 :: Only
|
Programming Language :: Python :: 3 :: Only
|
||||||
Programming Language :: Python :: 3.6
|
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
|
@ -31,8 +30,7 @@ install_requires =
|
||||||
toml
|
toml
|
||||||
virtualenv>=20.0.8
|
virtualenv>=20.0.8
|
||||||
importlib-metadata;python_version<"3.8"
|
importlib-metadata;python_version<"3.8"
|
||||||
importlib-resources<5.3;python_version<"3.7"
|
python_requires = >=3.7
|
||||||
python_requires = >=3.6.1
|
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
exclude =
|
exclude =
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -1,2 +1,4 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
setup()
|
setup()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
import shutil
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
LANGUAGES = [
|
LANGUAGES = [
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import gzip
|
import gzip
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -6,7 +8,6 @@ import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import tarfile
|
import tarfile
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Optional
|
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ from typing import Sequence
|
||||||
|
|
||||||
REPOS = (
|
REPOS = (
|
||||||
('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'),
|
('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'),
|
||||||
('ruby-build', 'https://github.com/rbenv/ruby-build', '8663d2f'),
|
('ruby-build', 'https://github.com/rbenv/ruby-build', 'a5ca3e4'),
|
||||||
(
|
(
|
||||||
'ruby-download',
|
'ruby-download',
|
||||||
'https://github.com/garnieretienne/rvm-download',
|
'https://github.com/garnieretienne/rvm-download',
|
||||||
|
@ -69,7 +70,7 @@ def make_archive(name: str, repo: str, ref: str, destdir: str) -> str:
|
||||||
return output_path
|
return output_path
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
def main(argv: Sequence[str] | None = None) -> int:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--dest', default='pre_commit/resources')
|
parser.add_argument('--dest', default='pre_commit/resources')
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
|
@ -2,5 +2,4 @@
|
||||||
name: Python 3 Hook
|
name: Python 3 Hook
|
||||||
entry: python3-hook
|
entry: python3-hook
|
||||||
language: python
|
language: python
|
||||||
language_version: python3
|
|
||||||
files: \.py$
|
files: \.py$
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM ubuntu:bionic
|
FROM ubuntu:focal
|
||||||
RUN : \
|
RUN : \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
@ -10,5 +10,5 @@ RUN : \
|
||||||
|
|
||||||
ENV LANG=C.UTF-8 PATH=/venv/bin:$PATH
|
ENV LANG=C.UTF-8 PATH=/venv/bin:$PATH
|
||||||
RUN : \
|
RUN : \
|
||||||
&& python3.6 -mvenv /venv \
|
&& python3 -mvenv /venv \
|
||||||
&& pip install --no-cache-dir pip setuptools wheel no-manylinux --upgrade
|
&& pip install --no-cache-dir pip setuptools wheel no-manylinux --upgrade
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
|
@ -59,9 +61,6 @@ def main() -> int:
|
||||||
if sys.platform == 'win32': # https://bugs.python.org/issue19124
|
if sys.platform == 'win32': # https://bugs.python.org/issue19124
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
if sys.version_info < (3, 7): # https://bugs.python.org/issue25942
|
|
||||||
return subprocess.Popen(cmd).wait()
|
|
||||||
else:
|
|
||||||
return subprocess.call(cmd)
|
return subprocess.call(cmd)
|
||||||
else:
|
else:
|
||||||
os.execvp(cmd[0], cmd)
|
os.execvp(cmd[0], cmd)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""A shim executable to put dependencies on sys.path"""
|
"""A shim executable to put dependencies on sys.path"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os.path
|
import os.path
|
||||||
import runpy
|
import runpy
|
||||||
|
@ -36,9 +38,6 @@ def main() -> int:
|
||||||
if sys.platform == 'win32': # https://bugs.python.org/issue19124
|
if sys.platform == 'win32': # https://bugs.python.org/issue19124
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
if sys.version_info < (3, 7): # https://bugs.python.org/issue25942
|
|
||||||
return subprocess.Popen(cmd).wait()
|
|
||||||
else:
|
|
||||||
return subprocess.call(cmd)
|
return subprocess.call(cmd)
|
||||||
else:
|
else:
|
||||||
os.execvp(cmd[0], cmd)
|
os.execvp(cmd[0], cmd)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import shlex
|
import shlex
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
@ -101,6 +103,24 @@ def test_rev_info_update_tags_only_does_not_pick_tip(tagged):
|
||||||
assert new_info.rev == 'v1.2.3'
|
assert new_info.rev == 'v1.2.3'
|
||||||
|
|
||||||
|
|
||||||
|
def test_rev_info_update_tags_prefers_version_tag(tagged, out_of_date):
|
||||||
|
cmd_output('git', 'tag', 'latest', cwd=out_of_date.path)
|
||||||
|
config = make_config_from_repo(tagged.path, rev=tagged.original_rev)
|
||||||
|
info = RevInfo.from_config(config)
|
||||||
|
new_info = info.update(tags_only=True, freeze=False)
|
||||||
|
assert new_info.rev == 'v1.2.3'
|
||||||
|
|
||||||
|
|
||||||
|
def test_rev_info_update_tags_non_version_tag(out_of_date):
|
||||||
|
cmd_output('git', 'tag', 'latest', cwd=out_of_date.path)
|
||||||
|
config = make_config_from_repo(
|
||||||
|
out_of_date.path, rev=out_of_date.original_rev,
|
||||||
|
)
|
||||||
|
info = RevInfo.from_config(config)
|
||||||
|
new_info = info.update(tags_only=True, freeze=False)
|
||||||
|
assert new_info.rev == 'latest'
|
||||||
|
|
||||||
|
|
||||||
def test_rev_info_update_freeze_tag(tagged):
|
def test_rev_info_update_freeze_tag(tagged):
|
||||||
git_commit(cwd=tagged.path)
|
git_commit(cwd=tagged.path)
|
||||||
config = make_config_from_repo(tagged.path, rev=tagged.original_rev)
|
config = make_config_from_repo(tagged.path, rev=tagged.original_rev)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -5,6 +7,7 @@ import re_assert
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
|
from pre_commit.commands.install_uninstall import _hook_types
|
||||||
from pre_commit.commands.install_uninstall import CURRENT_HASH
|
from pre_commit.commands.install_uninstall import CURRENT_HASH
|
||||||
from pre_commit.commands.install_uninstall import install
|
from pre_commit.commands.install_uninstall import install
|
||||||
from pre_commit.commands.install_uninstall import install_hooks
|
from pre_commit.commands.install_uninstall import install_hooks
|
||||||
|
@ -25,6 +28,36 @@ from testing.util import cwd
|
||||||
from testing.util import git_commit
|
from testing.util import git_commit
|
||||||
|
|
||||||
|
|
||||||
|
def test_hook_types_explicitly_listed():
|
||||||
|
assert _hook_types(os.devnull, ['pre-push']) == ['pre-push']
|
||||||
|
|
||||||
|
|
||||||
|
def test_hook_types_default_value_when_not_specified():
|
||||||
|
assert _hook_types(os.devnull, None) == ['pre-commit']
|
||||||
|
|
||||||
|
|
||||||
|
def test_hook_types_configured(tmpdir):
|
||||||
|
cfg = tmpdir.join('t.cfg')
|
||||||
|
cfg.write('default_install_hook_types: [pre-push]\nrepos: []\n')
|
||||||
|
|
||||||
|
assert _hook_types(str(cfg), None) == ['pre-push']
|
||||||
|
|
||||||
|
|
||||||
|
def test_hook_types_configured_nonsense(tmpdir):
|
||||||
|
cfg = tmpdir.join('t.cfg')
|
||||||
|
cfg.write('default_install_hook_types: []\nrepos: []\n')
|
||||||
|
|
||||||
|
# hopefully the user doesn't do this, but the code allows it!
|
||||||
|
assert _hook_types(str(cfg), None) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_hook_types_configuration_has_error(tmpdir):
|
||||||
|
cfg = tmpdir.join('t.cfg')
|
||||||
|
cfg.write('[')
|
||||||
|
|
||||||
|
assert _hook_types(str(cfg), None) == ['pre-commit']
|
||||||
|
|
||||||
|
|
||||||
def test_is_not_script():
|
def test_is_not_script():
|
||||||
assert is_our_script('setup.py') is False
|
assert is_our_script('setup.py') is False
|
||||||
|
|
||||||
|
@ -59,7 +92,7 @@ def test_install_multiple_hooks_at_once(in_git_dir, store):
|
||||||
install(C.CONFIG_FILE, store, hook_types=['pre-commit', 'pre-push'])
|
install(C.CONFIG_FILE, store, hook_types=['pre-commit', 'pre-push'])
|
||||||
assert in_git_dir.join('.git/hooks/pre-commit').exists()
|
assert in_git_dir.join('.git/hooks/pre-commit').exists()
|
||||||
assert in_git_dir.join('.git/hooks/pre-push').exists()
|
assert in_git_dir.join('.git/hooks/pre-push').exists()
|
||||||
uninstall(hook_types=['pre-commit', 'pre-push'])
|
uninstall(C.CONFIG_FILE, hook_types=['pre-commit', 'pre-push'])
|
||||||
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
||||||
assert not in_git_dir.join('.git/hooks/pre-push').exists()
|
assert not in_git_dir.join('.git/hooks/pre-push').exists()
|
||||||
|
|
||||||
|
@ -77,14 +110,14 @@ def test_install_hooks_dead_symlink(in_git_dir, store):
|
||||||
|
|
||||||
|
|
||||||
def test_uninstall_does_not_blow_up_when_not_there(in_git_dir):
|
def test_uninstall_does_not_blow_up_when_not_there(in_git_dir):
|
||||||
assert uninstall(hook_types=['pre-commit']) == 0
|
assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_uninstall(in_git_dir, store):
|
def test_uninstall(in_git_dir, store):
|
||||||
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
||||||
install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
|
install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
|
||||||
assert in_git_dir.join('.git/hooks/pre-commit').exists()
|
assert in_git_dir.join('.git/hooks/pre-commit').exists()
|
||||||
uninstall(hook_types=['pre-commit'])
|
uninstall(C.CONFIG_FILE, hook_types=['pre-commit'])
|
||||||
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
||||||
|
|
||||||
|
|
||||||
|
@ -414,7 +447,7 @@ def test_uninstall_restores_legacy_hooks(tempdir_factory, store):
|
||||||
|
|
||||||
# Now install and uninstall pre-commit
|
# Now install and uninstall pre-commit
|
||||||
assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
|
assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
|
||||||
assert uninstall(hook_types=['pre-commit']) == 0
|
assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0
|
||||||
|
|
||||||
# Make sure we installed the "old" hook correctly
|
# Make sure we installed the "old" hook correctly
|
||||||
ret, output = _get_commit_output(tempdir_factory, touch_file='baz')
|
ret, output = _get_commit_output(tempdir_factory, touch_file='baz')
|
||||||
|
@ -449,7 +482,7 @@ def test_uninstall_doesnt_remove_not_our_hooks(in_git_dir):
|
||||||
pre_commit.write('#!/usr/bin/env bash\necho 1\n')
|
pre_commit.write('#!/usr/bin/env bash\necho 1\n')
|
||||||
make_executable(pre_commit.strpath)
|
make_executable(pre_commit.strpath)
|
||||||
|
|
||||||
assert uninstall(hook_types=['pre-commit']) == 0
|
assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0
|
||||||
|
|
||||||
assert pre_commit.exists()
|
assert pre_commit.exists()
|
||||||
|
|
||||||
|
@ -1005,3 +1038,16 @@ def test_install_temporarily_allow_mising_config(tempdir_factory, store):
|
||||||
'Skipping `pre-commit`.'
|
'Skipping `pre-commit`.'
|
||||||
)
|
)
|
||||||
assert expected in output
|
assert expected in output
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_uninstall_default_hook_types(in_git_dir, store):
|
||||||
|
cfg_src = 'default_install_hook_types: [pre-commit, pre-push]\nrepos: []\n'
|
||||||
|
in_git_dir.join(C.CONFIG_FILE).write(cfg_src)
|
||||||
|
|
||||||
|
assert not install(C.CONFIG_FILE, store, hook_types=None)
|
||||||
|
assert os.access(in_git_dir.join('.git/hooks/pre-commit').strpath, os.X_OK)
|
||||||
|
assert os.access(in_git_dir.join('.git/hooks/pre-push').strpath, os.X_OK)
|
||||||
|
|
||||||
|
assert not uninstall(C.CONFIG_FILE, hook_types=None)
|
||||||
|
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
|
||||||
|
assert not in_git_dir.join('.git/hooks/pre-push').exists()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit.commands.migrate_config import migrate_config
|
from pre_commit.commands.migrate_config import migrate_config
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from pre_commit.commands.sample_config import sample_config
|
from pre_commit.commands.sample_config import sample_config
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -19,6 +21,20 @@ def test_get_root_deeper(in_git_dir):
|
||||||
assert os.path.normcase(git.get_root()) == expected
|
assert os.path.normcase(git.get_root()) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_root_in_git_sub_dir(in_git_dir):
|
||||||
|
expected = os.path.normcase(in_git_dir.strpath)
|
||||||
|
with pytest.raises(FatalError):
|
||||||
|
with in_git_dir.join('.git/objects').ensure_dir().as_cwd():
|
||||||
|
assert os.path.normcase(git.get_root()) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_root_not_in_working_dir(in_git_dir):
|
||||||
|
expected = os.path.normcase(in_git_dir.strpath)
|
||||||
|
with pytest.raises(FatalError):
|
||||||
|
with in_git_dir.join('..').ensure_dir().as_cwd():
|
||||||
|
assert os.path.normcase(git.get_root()) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_in_exactly_dot_git(in_git_dir):
|
def test_in_exactly_dot_git(in_git_dir):
|
||||||
with in_git_dir.join('.git').as_cwd(), pytest.raises(FatalError):
|
with in_git_dir.join('.git').as_cwd(), pytest.raises(FatalError):
|
||||||
git.get_root()
|
git.get_root()
|
||||||
|
@ -38,6 +54,22 @@ def test_get_root_bare_worktree(tmpdir):
|
||||||
assert git.get_root() == os.path.abspath('.')
|
assert git.get_root() == os.path.abspath('.')
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_git_dir(tmpdir):
|
||||||
|
"""Regression test for #1972"""
|
||||||
|
src = tmpdir.join('src').ensure_dir()
|
||||||
|
cmd_output('git', 'init', str(src))
|
||||||
|
git_commit(cwd=str(src))
|
||||||
|
|
||||||
|
worktree = tmpdir.join('worktree').ensure_dir()
|
||||||
|
cmd_output('git', 'worktree', 'add', '../worktree', cwd=src)
|
||||||
|
|
||||||
|
with worktree.as_cwd():
|
||||||
|
assert git.get_git_dir() == src.ensure_dir(
|
||||||
|
'.git/worktrees/worktree',
|
||||||
|
)
|
||||||
|
assert git.get_git_common_dir() == src.ensure_dir('.git')
|
||||||
|
|
||||||
|
|
||||||
def test_get_root_worktree_in_git(tmpdir):
|
def test_get_root_worktree_in_git(tmpdir):
|
||||||
src = tmpdir.join('src').ensure_dir()
|
src = tmpdir.join('src').ensure_dir()
|
||||||
cmd_output('git', 'init', str(src))
|
cmd_output('git', 'init', str(src))
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pre_commit import envcontext
|
from pre_commit import envcontext
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import builtins
|
import builtins
|
||||||
import json
|
import json
|
||||||
import ntpath
|
import ntpath
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pre_commit.languages.golang import guess_go_dir
|
from pre_commit.languages.golang import guess_go_dir
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
@ -86,7 +88,9 @@ def test_assert_no_additional_deps():
|
||||||
helpers.assert_no_additional_deps('lang', ['hmmm'])
|
helpers.assert_no_additional_deps('lang', ['hmmm'])
|
||||||
msg, = excinfo.value.args
|
msg, = excinfo.value.args
|
||||||
assert msg == (
|
assert msg == (
|
||||||
'For now, pre-commit does not support additional_dependencies for lang'
|
'for now, pre-commit does not support additional_dependencies for '
|
||||||
|
'lang -- '
|
||||||
|
"you selected `additional_dependencies: ['hmmm']`"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pre_commit.languages import pygrep
|
from pre_commit.languages import pygrep
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
@ -47,16 +49,16 @@ def test_norm_version_of_default_is_sys_executable():
|
||||||
assert python.norm_version('default') is None
|
assert python.norm_version('default') is None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('v', ('python3.6', 'python3', 'python'))
|
@pytest.mark.parametrize('v', ('python3.9', 'python3', 'python'))
|
||||||
def test_sys_executable_matches(v):
|
def test_sys_executable_matches(v):
|
||||||
with mock.patch.object(sys, 'version_info', (3, 6, 7)):
|
with mock.patch.object(sys, 'version_info', (3, 9, 10)):
|
||||||
assert python._sys_executable_matches(v)
|
assert python._sys_executable_matches(v)
|
||||||
assert python.norm_version(v) is None
|
assert python.norm_version(v) is None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('v', ('notpython', 'python3.x'))
|
@pytest.mark.parametrize('v', ('notpython', 'python3.x'))
|
||||||
def test_sys_executable_matches_does_not_match(v):
|
def test_sys_executable_matches_does_not_match(v):
|
||||||
with mock.patch.object(sys, 'version_info', (3, 6, 7)):
|
with mock.patch.object(sys, 'version_info', (3, 9, 10)):
|
||||||
assert not python._sys_executable_matches(v)
|
assert not python._sys_executable_matches(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +67,7 @@ def test_sys_executable_matches_does_not_match(v):
|
||||||
('/usr/bin/python3', '/usr/bin/python3.7', 'python3'),
|
('/usr/bin/python3', '/usr/bin/python3.7', 'python3'),
|
||||||
('/usr/bin/python', '/usr/bin/python3.7', 'python3.7'),
|
('/usr/bin/python', '/usr/bin/python3.7', 'python3.7'),
|
||||||
('/usr/bin/python', '/usr/bin/python', None),
|
('/usr/bin/python', '/usr/bin/python', None),
|
||||||
('/usr/bin/python3.6m', '/usr/bin/python3.6m', 'python3.6m'),
|
('/usr/bin/python3.7m', '/usr/bin/python3.7m', 'python3.7m'),
|
||||||
('v/bin/python', 'v/bin/pypy', 'pypy'),
|
('v/bin/python', 'v/bin/pypy', 'pypy'),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue