Get black working as a linter

This commit is contained in:
Reid 'arrdem' McKenzie 2021-09-02 22:10:12 -06:00
parent 84d197d1ae
commit b7e86e50bf
4 changed files with 139 additions and 1 deletions

10
tools/black/BUILD Normal file
View file

@ -0,0 +1,10 @@
py_binary(
name = "black",
main = "__main__.py",
deps = [
py_requirement("black"),
],
visibility = [
"//visibility:public"
],
)

57
tools/black/__main__.py Normal file
View file

@ -0,0 +1,57 @@
"""A shim to black which knows how to tee output."""
import argparse
from contextlib import contextmanager
import sys
from black import patched_main
parser = argparse.ArgumentParser()
parser.add_argument("--output-file", default=None)
class Tee(object):
"""Tee all I/O to a file and stdout."""
def __init__(self, name, mode):
self._file = open(name, mode)
self._stdout = sys.stdout
def __enter__(self):
sys.stdout = self
return self
def __exit__(self, *args, **kwargs):
sys.stdout = self._stdout
self.close()
def write(self, data):
self._file.write(data)
self._stdout.write(data)
def flush(self):
self._file.flush()
self._stdout.flush()
def close(self):
self._file.close()
@contextmanager
def nullctx():
yield
if __name__ == "__main__":
opts, args = parser.parse_known_args()
if opts.output_file:
print("Teeig output....")
ctx = Tee(opts.output_file, "w")
else:
ctx = nullctx()
with ctx:
sys.argv = [sys.argv[0]] + args
patched_main()

71
tools/black/black.bzl Normal file
View file

@ -0,0 +1,71 @@
"""Linting for Python using Aspects."""
# Hacked up from https://github.com/bazelbuild/rules_rust/blob/main/rust/private/clippy.bzl
#
# Usage:
# bazel build --aspects="//tools/flake8:flake8.bzl%flake8_aspect" --output_groups=flake8_checks <target|pattern>
#
# Note that the build directive can be inserted to .bazelrc to make it part of the default behavior
def _black_aspect_impl(target, ctx):
if hasattr(ctx.rule.attr, 'srcs'):
black = ctx.attr._black.files_to_run
config = ctx.attr._config.files.to_list()[0]
files = []
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if f.extension == "py":
files.append(f)
if files:
report = ctx.actions.declare_file(ctx.label.name + ".black.report")
else:
return []
args = ["--check", "--output-file", report.path]
for f in files:
args.append(f.path)
ctx.actions.run(
executable = black,
inputs = files,
tools = ctx.attr._config.files.to_list() + ctx.attr._black.files.to_list(),
arguments = args,
outputs = [report],
mnemonic = "Black",
)
return [
OutputGroupInfo(black_checks = depset([report]))
]
return []
black_aspect = aspect(
implementation = _black_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'_black': attr.label(default=":black"),
'_config': attr.label(
default="//:setup.cfg",
executable=False,
allow_single_file=True
),
}
)
def _black_rule_impl(ctx):
ready_targets = [dep for dep in ctx.attr.deps if "black_checks" in dir(dep[OutputGroupInfo])]
files = depset([], transitive = [dep[OutputGroupInfo].black_checks for dep in ready_targets])
return [DefaultInfo(files = files)]
black = rule(
implementation = _black_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [black_aspect]),
},
)

View file

@ -19,7 +19,7 @@ def _flake8_aspect_impl(target, ctx):
files.append(f) files.append(f)
if files: if files:
report = ctx.actions.declare_file(ctx.label.name + ".report") report = ctx.actions.declare_file(ctx.label.name + ".flake.report")
else: else:
return [] return []