generated from bazel-contrib/rules-template
-
-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathflake8.bzl
132 lines (107 loc) · 4.54 KB
/
flake8.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""API for declaring a flake8 lint aspect that visits py_library rules.
Typical usage:
First, fetch the flake8 package via your standard requirements file and pip calls.
Then, declare a binary target for it, typically in `tools/lint/BUILD.bazel`:
```starlark
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
py_console_script_binary(
name = "flake8",
pkg = "@pip//flake8:pkg",
)
```
Finally, create the linter aspect, typically in `tools/lint/linters.bzl`:
```starlark
load("@aspect_rules_lint//lint:flake8.bzl", "lint_flake8_aspect")
flake8 = lint_flake8_aspect(
binary = "@@//tools/lint:flake8",
config = "@@//:.flake8",
)
```
"""
load("//lint/private:lint_aspect.bzl", "LintOptionsInfo", "filter_srcs", "noop_lint_action", "output_files", "should_visit")
_MNEMONIC = "AspectRulesLintFlake8"
def flake8_action(ctx, executable, srcs, config, stdout, exit_code = None, options = []):
"""Run flake8 as an action under Bazel.
Based on https://flake8.pycqa.org/en/latest/user/invocation.html
Args:
ctx: Bazel Rule or Aspect evaluation context
executable: label of the the flake8 program
srcs: python files to be linted
config: label of the flake8 config file (setup.cfg, tox.ini, or .flake8)
stdout: output file containing stdout of flake8
exit_code: output file containing exit code of flake8
If None, then fail the build when flake8 exits non-zero.
options: additional command-line options, see https://flake8.pycqa.org/en/latest/user/options.html
"""
inputs = srcs + [config]
outputs = [stdout]
# Wire command-line options, see
# https://flake8.pycqa.org/en/latest/user/options.html
args = ctx.actions.args()
args.add_all(options)
args.add_all(srcs)
args.add(config, format = "--config=%s")
if exit_code:
command = "{flake8} $@ >{stdout}; echo $? > " + exit_code.path
outputs.append(exit_code)
else:
# Create empty stdout file on success, as Bazel expects one
command = "{flake8} $@ && touch {stdout}"
ctx.actions.run_shell(
inputs = inputs,
outputs = outputs,
tools = [executable],
command = command.format(flake8 = executable.path, stdout = stdout.path),
arguments = [args],
mnemonic = _MNEMONIC,
progress_message = "Linting %{label} with Flake8",
)
# buildifier: disable=function-docstring
def _flake8_aspect_impl(target, ctx):
# Note: we don't inspect whether PyInfo in target to avoid a dep on rules_python
if not should_visit(ctx.rule, ctx.attr._rule_kinds):
return []
outputs, info = output_files(_MNEMONIC, target, ctx)
files_to_lint = filter_srcs(ctx.rule)
if len(files_to_lint) == 0:
noop_lint_action(ctx, outputs)
return [info]
color_options = ["--color=always"] if ctx.attr._options[LintOptionsInfo].color else []
flake8_action(ctx, ctx.executable._flake8, files_to_lint, ctx.file._config_file, outputs.human.out, outputs.human.exit_code, color_options)
flake8_action(ctx, ctx.executable._flake8, files_to_lint, ctx.file._config_file, outputs.machine.out, outputs.machine.exit_code)
return [info]
def lint_flake8_aspect(binary, config, rule_kinds = ["py_binary", "py_library"]):
"""A factory function to create a linter aspect.
Attrs:
binary: a flake8 executable. Can be obtained from rules_python like so:
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
py_console_script_binary(
name = "flake8",
pkg = "@pip//flake8:pkg",
)
config: the flake8 config file (`setup.cfg`, `tox.ini`, or `.flake8`)
"""
return aspect(
implementation = _flake8_aspect_impl,
# Edges we need to walk up the graph from the selected targets.
# Needed for linters that need semantic information like transitive type declarations.
# attr_aspects = ["deps"],
attrs = {
"_options": attr.label(
default = "//lint:options",
providers = [LintOptionsInfo],
),
"_flake8": attr.label(
default = binary,
executable = True,
cfg = "exec",
),
"_config_file": attr.label(
default = config,
allow_single_file = True,
),
"_rule_kinds": attr.string_list(
default = rule_kinds,
),
},
)