Skip to content

Commit

Permalink
fix: Ensure sublack integration for all project files
Browse files Browse the repository at this point in the history
Previously [sublack](https://github.com/jgirardet/sublack) integration
via `pre-commit-run-black-entry` works only for files from project root,
this commit fixes that and ensure it now works for all project files.

To achieve that `main_black` (and `main`) changed to,

- Find project's root `.pre-commit-config.yaml` file
- Find project's root `pyproject.toml` file
- Print `tmp_path` content within `main_black` function
  • Loading branch information
playpauseandstop committed Jun 11, 2020
1 parent a2d1a1a commit 09c7134
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 16 deletions.
91 changes: 77 additions & 14 deletions pre_commit_run_hook_entry.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import argparse
import os
import sys
import tempfile
from contextlib import contextmanager
from pathlib import Path
from typing import cast, Iterator, NamedTuple, Optional, Sequence, Tuple
from typing import (
Callable,
cast,
Iterator,
NamedTuple,
Optional,
Sequence,
Tuple,
)

from pre_commit import git
from pre_commit.clientlib import load_config
Expand All @@ -21,17 +28,20 @@
from pre_commit.store import Store


ARG_CONFIG = "--config"
ARG_DIFF = "--diff"
ARG_QUIET = "--quiet"
ARG_STDIN = "-"
ARG_BREAK = "--"
CHUNK_SIZE = 4096
HOOK_BLACK = "black"

Argv = Sequence[str]

__prog__ = "pre-commit-run-hook-entry"
__author__ = "Igor Davdenko"
__license__ = "BSD-3-Clause"
__version__ = "1.0.0a0"
__version__ = "1.0.0a1"


class HookContext(NamedTuple):
Expand All @@ -40,6 +50,17 @@ class HookContext(NamedTuple):
tmp_path: Optional[Path] = None


def find_file(file_name: str, *, path: Path = None) -> Optional[Path]:
if path is None:
path = Path.cwd()
maybe_file = path / file_name
if maybe_file.exists():
return maybe_file.absolute()
if path.parent != path:
return find_file(file_name, path=path.parent)
return None


def find_hook(args: argparse.Namespace, store: Store) -> Hook:
config = load_config(args.config)
hooks = [
Expand Down Expand Up @@ -82,12 +103,19 @@ def get_args(argv: Argv) -> Tuple[str, Argv]:
return (argv[idx + 1], (*argv[:idx], *argv[next_idx:]))


def get_pre_commit_args(hook: str) -> argparse.Namespace:
def get_pre_commit_args(
hook: str, *, config: Path = None
) -> argparse.Namespace:
parser = argparse.ArgumentParser()
_add_color_option(parser)
_add_config_option(parser)
_add_run_options(parser)
return parser.parse_args([hook])

args = [hook]
if config:
args += ["--config", str(config)]

return parser.parse_args(args)


@contextmanager
Expand All @@ -107,7 +135,12 @@ def hook_context(argv: Argv) -> Iterator[HookContext]:
tmp_path.unlink()


def main(argv: Argv = None) -> int:
def main(
argv: Argv = None,
*,
pre_commit_config_yaml: Path = None,
tmp_path_func: Callable[[Path], None] = None,
) -> int:
if argv is None:
argv = sys.argv[1:]

Expand All @@ -119,7 +152,9 @@ def main(argv: Argv = None) -> int:
if hook.startswith("-"):
return usage()

pre_commit_args = get_pre_commit_args(hook)
pre_commit_args = get_pre_commit_args(
hook, config=pre_commit_config_yaml
)

with error_handler(), logging_handler(pre_commit_args.color):
git.check_for_cygwin_mismatch()
Expand All @@ -133,8 +168,8 @@ def main(argv: Argv = None) -> int:
patch_hook(original_hook, extra_args), pre_commit_args.color
)

if tmp_path and hook == HOOK_BLACK and ARG_DIFF not in extra_args:
sys.stdout.buffer.write(tmp_path.read_bytes())
if tmp_path and tmp_path_func:
tmp_path_func(tmp_path)

sys.stdout.buffer.write(out)
sys.stdout.buffer.flush()
Expand All @@ -143,14 +178,42 @@ def main(argv: Argv = None) -> int:


def main_black(argv: Argv = None) -> int:
"""Special case for run black pre-commit hook for `sublack`_ needs.
Unlike other Sublime Text 3 plugins, sublack calls ``black_command`` from
file directory, not from project root. As well, as unlike black integration
for VS Code sublack expects on whole formatted file by default, not on
their diff.
That results in necessity of,
- Finding root ``.pre-commit-config.yaml`` file for pre-commit
- Finding root ``pyproject.toml`` file for black config
- Print content of tmp path into stdout
.. _sublack: https://github.com/jgirardet/sublack
"""

def print_tmp_path(tmp_path: Path) -> None:
# TODO: Print file content by chunks
sys.stdout.buffer.write(tmp_path.read_bytes())

# Setup black arguments
args = [HOOK_BLACK, ARG_BREAK, "--quiet"]

maybe_pyproject = Path(os.getcwd()) / "pyproject.toml"
if maybe_pyproject.exists():
args.extend(["--config", str(maybe_pyproject)])
pyproject_toml = find_file("pyproject.toml")
if pyproject_toml:
args += [ARG_CONFIG, str(pyproject_toml)]

args += argv or sys.argv[1:]

args.extend(argv or sys.argv[1:])
return main(args)
# Special case of calling ``pre-commit-run-hook-entry``
pre_commit_config_yaml = find_file(".pre-commit-config.yaml")
return main(
args,
pre_commit_config_yaml=pre_commit_config_yaml,
tmp_path_func=print_tmp_path,
)


def patch_hook(hook: Hook, extra_args: Argv) -> Hook:
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ line_length = 79

[tool.poetry]
name = "pre-commit-run-hook-entry"
version = "1.0.0a0"
version = "1.0.0a1"
description = "Run pre-commit hook entry. Allow to run pre-commit hooks for text editor formatting / linting needs."
authors = ["Igor Davydenko <iam@igordavydenko.com>"]
license = "BSD-3-Clause"
Expand All @@ -17,7 +17,6 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Utilities",
"Typing :: Typed"
Expand Down

0 comments on commit 09c7134

Please sign in to comment.