diff options
Diffstat (limited to 'pre_commit')
-rw-r--r-- | pre_commit/color.py | 10 | ||||
-rw-r--r-- | pre_commit/commands/autoupdate.py | 4 | ||||
-rw-r--r-- | pre_commit/commands/hook_impl.py | 31 | ||||
-rw-r--r-- | pre_commit/commands/run.py | 12 | ||||
-rw-r--r-- | pre_commit/languages/docker.py | 8 | ||||
-rw-r--r-- | pre_commit/languages/node.py | 16 | ||||
-rw-r--r-- | pre_commit/languages/python.py | 6 |
7 files changed, 67 insertions, 20 deletions
diff --git a/pre_commit/color.py b/pre_commit/color.py index 5fa7042..eb906b7 100644 --- a/pre_commit/color.py +++ b/pre_commit/color.py @@ -11,7 +11,7 @@ if sys.platform == 'win32': # pragma: no cover (windows) from ctypes.wintypes import DWORD from ctypes.wintypes import HANDLE - STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 def bool_errcheck(result, func, args): @@ -40,9 +40,9 @@ if sys.platform == 'win32': # pragma: no cover (windows) # # More info on the escape sequences supported: # https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx - stdout = GetStdHandle(STD_OUTPUT_HANDLE) - flags = GetConsoleMode(stdout) - SetConsoleMode(stdout, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING) + stderr = GetStdHandle(STD_ERROR_HANDLE) + flags = GetConsoleMode(stderr) + SetConsoleMode(stderr, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING) try: _enable() @@ -90,7 +90,7 @@ def use_color(setting: str) -> bool: return ( setting == 'always' or ( setting == 'auto' and - sys.stdout.isatty() and + sys.stderr.isatty() and terminal_supports_color and os.getenv('TERM') != 'dumb' ) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 5a9a988..8c9fdd7 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -93,7 +93,7 @@ def _original_lines( retry: bool = False, ) -> Tuple[List[str], List[int]]: """detect `rev:` lines or reformat the file""" - with open(path) as f: + with open(path, newline='') as f: original = f.read() lines = original.splitlines(True) @@ -126,7 +126,7 @@ def _write_new_config(path: str, rev_infos: List[Optional[RevInfo]]) -> None: comment = match[4] lines[idx] = f'{match[1]}rev:{match[2]}{new_rev}{comment}{match[5]}' - with open(path, 'w') as f: + with open(path, 'w', newline='') as f: f.write(''.join(lines)) diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index 5ff4555..4843fc7 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -147,15 +147,44 @@ def _pre_push_ns( return None +_EXPECTED_ARG_LENGTH_BY_HOOK = { + 'commit-msg': 1, + 'post-checkout': 3, + 'pre-commit': 0, + 'pre-merge-commit': 0, + 'pre-push': 2, +} + + +def _check_args_length(hook_type: str, args: Sequence[str]) -> None: + if hook_type == 'prepare-commit-msg': + if len(args) < 1 or len(args) > 3: + raise SystemExit( + f'hook-impl for {hook_type} expected 1, 2, or 3 arguments ' + f'but got {len(args)}: {args}', + ) + elif hook_type in _EXPECTED_ARG_LENGTH_BY_HOOK: + expected = _EXPECTED_ARG_LENGTH_BY_HOOK[hook_type] + if len(args) != expected: + arguments_s = 'argument' if expected == 1 else 'arguments' + raise SystemExit( + f'hook-impl for {hook_type} expected {expected} {arguments_s} ' + f'but got {len(args)}: {args}', + ) + else: + raise AssertionError(f'unexpected hook type: {hook_type}') + + def _run_ns( hook_type: str, color: bool, args: Sequence[str], stdin: bytes, ) -> Optional[argparse.Namespace]: + _check_args_length(hook_type, args) if hook_type == 'pre-push': return _pre_push_ns(color, args, stdin) - elif hook_type in {'prepare-commit-msg', 'commit-msg'}: + elif hook_type in {'commit-msg', 'prepare-commit-msg'}: return _ns(hook_type, color, commit_msg_filename=args[0]) elif hook_type in {'pre-merge-commit', 'pre-commit'}: return _ns(hook_type, color) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 2f74578..8c8401c 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -6,6 +6,7 @@ import os import re import subprocess import time +import unicodedata from typing import Any from typing import Collection from typing import Dict @@ -33,8 +34,13 @@ from pre_commit.util import EnvironT logger = logging.getLogger('pre_commit') +def _len_cjk(msg: str) -> int: + widths = {'A': 1, 'F': 2, 'H': 1, 'N': 1, 'Na': 1, 'W': 2} + return sum(widths[unicodedata.east_asian_width(c)] for c in msg) + + def _start_msg(*, start: str, cols: int, end_len: int) -> str: - dots = '.' * (cols - len(start) - end_len - 1) + dots = '.' * (cols - _len_cjk(start) - end_len - 1) return f'{start}{dots}' @@ -47,7 +53,7 @@ def _full_msg( use_color: bool, postfix: str = '', ) -> str: - dots = '.' * (cols - len(start) - len(postfix) - len(end_msg) - 1) + dots = '.' * (cols - _len_cjk(start) - len(postfix) - len(end_msg) - 1) end = color.format_color(end_msg, end_color, use_color) return f'{start}{dots}{postfix}{end}\n' @@ -206,7 +212,7 @@ def _compute_cols(hooks: Sequence[Hook]) -> int: Hook name...(no files to check) Skipped """ if hooks: - name_len = max(len(hook.name) for hook in hooks) + name_len = max(_len_cjk(hook.name) for hook in hooks) else: name_len = 0 diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index f449584..4091492 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -76,18 +76,18 @@ def install_environment( os.mkdir(directory) -def get_docker_user() -> str: # pragma: win32 no cover +def get_docker_user() -> Tuple[str, ...]: # pragma: win32 no cover try: - return f'{os.getuid()}:{os.getgid()}' + return ('-u', f'{os.getuid()}:{os.getgid()}') except AttributeError: - return '1000:1000' + return () def docker_cmd() -> Tuple[str, ...]: # pragma: win32 no cover return ( 'docker', 'run', '--rm', - '-u', get_docker_user(), + *get_docker_user(), # https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from # The `Z` option tells Docker to label the content with a private # unshared label. Only the current container can use a private volume. diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 79ff807..9b636d3 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -1,4 +1,5 @@ import contextlib +import functools import os import sys from typing import Generator @@ -6,6 +7,7 @@ from typing import Sequence from typing import Tuple import pre_commit.constants as C +from pre_commit import parse_shebang from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -18,10 +20,22 @@ from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'node_env' -get_default_version = helpers.basic_get_default_version healthy = helpers.basic_healthy +@functools.lru_cache(maxsize=1) +def get_default_version() -> str: + # nodeenv does not yet support `-n system` on windows + if sys.platform == 'win32': + return C.DEFAULT + # if node is already installed, we can save a bunch of setup time by + # using the installed version + elif all(parse_shebang.find_executable(exe) for exe in ('node', 'npm')): + return 'system' + else: + return C.DEFAULT + + def _envdir(prefix: Prefix, version: str) -> str: directory = helpers.environment_dir(ENVIRONMENT_DIR, version) return prefix.path(directory) diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 5073a8b..85d8281 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -182,8 +182,8 @@ def py_interface( version: str, additional_dependencies: Sequence[str], ) -> None: - additional_dependencies = tuple(additional_dependencies) directory = helpers.environment_dir(_dir, version) + install = ('python', '-mpip', 'install', '.', *additional_dependencies) env_dir = prefix.path(directory) with clean_path_on_failure(env_dir): @@ -193,9 +193,7 @@ def py_interface( python = os.path.realpath(sys.executable) _make_venv(env_dir, python) with in_env(prefix, version): - helpers.run_setup_cmd( - prefix, ('pip', 'install', '.') + additional_dependencies, - ) + helpers.run_setup_cmd(prefix, install) return in_env, healthy, run_hook, install_environment |