4
4
import re
5
5
from dataclasses import dataclass
6
6
from pathlib import Path
7
- from typing import Any , Set
7
+ from typing import Any , Set , Tuple
8
8
9
9
from pants .backend .python .rules .pex import CreatePex , Pex , PexInterpreterContraints , PexRequirements
10
10
from pants .backend .python .subsystems .black import Black
11
11
from pants .backend .python .subsystems .python_setup import PythonSetup
12
12
from pants .backend .python .subsystems .subprocess_environment import SubprocessEncodingEnvironment
13
13
from pants .engine .fs import Digest , DirectoriesToMerge , PathGlobs , Snapshot
14
- from pants .engine .isolated_process import ExecuteProcessRequest , ExecuteProcessResult
14
+ from pants .engine .isolated_process import (
15
+ ExecuteProcessRequest ,
16
+ ExecuteProcessResult ,
17
+ FallibleExecuteProcessResult ,
18
+ )
15
19
from pants .engine .legacy .structs import (
16
20
PantsPluginAdaptor ,
17
21
PythonAppAdaptor ,
21
25
)
22
26
from pants .engine .rules import UnionRule , optionable_rule , rule
23
27
from pants .engine .selectors import Get
24
- from pants .rules .core .fmt import FmtResult , FmtTarget
28
+ from pants .rules .core .fmt import FmtResult , TargetWithSources
29
+ from pants .rules .core .lint import LintResult
25
30
26
31
27
32
# Note: this is a workaround until https://github.com/pantsbuild/pants/issues/8343 is addressed
@@ -32,13 +37,18 @@ class FormattablePythonTarget:
32
37
target : Any
33
38
34
39
40
+ @dataclass (frozen = True )
41
+ class BlackInput :
42
+ config_path : Path
43
+ resolved_requirements_pex : Pex
44
+ merged_input_files : Digest
45
+
46
+
35
47
@rule
36
- def run_black (
48
+ def get_black_input (
37
49
wrapped_target : FormattablePythonTarget ,
38
50
black : Black ,
39
- python_setup : PythonSetup ,
40
- subprocess_encoding_environment : SubprocessEncodingEnvironment ,
41
- ) -> FmtResult :
51
+ ) -> BlackInput :
42
52
config_path = black .get_options ().config
43
53
config_snapshot = yield Get (Snapshot , PathGlobs (include = (config_path ,)))
44
54
@@ -62,28 +72,58 @@ def run_black(
62
72
Digest ,
63
73
DirectoriesToMerge (directories = tuple (all_input_digests )),
64
74
)
75
+ yield BlackInput (config_path , resolved_requirements_pex , merged_input_files )
65
76
77
+
78
+ def _generate_black_pex_args (files : Set [str ], config_path : str , * , check_only : bool ) -> Tuple [str , ...]:
66
79
# The exclude option from Black only works on recursive invocations,
67
80
# so call black with the directories in which the files are present
68
81
# and passing the full file names with the include option
69
82
dirs : Set [str ] = set ()
70
- for filename in target . sources . snapshot . files :
83
+ for filename in files :
71
84
dirs .add (f"{ Path (filename ).parent } " )
72
85
pex_args = tuple (sorted (dirs ))
86
+ if check_only :
87
+ pex_args += ("--check" , )
73
88
if config_path :
74
89
pex_args += ("--config" , config_path )
75
- if target .sources .snapshot .files :
76
- pex_args += ("--include" , "|" .join (re .escape (f ) for f in target .sources .snapshot .files ))
90
+ if files :
91
+ pex_args += ("--include" , "|" .join (re .escape (f ) for f in files ))
92
+ return pex_args
93
+
77
94
78
- request = resolved_requirements_pex .create_execute_request (
95
+ def _generate_black_request (
96
+ wrapped_target : FormattablePythonTarget ,
97
+ black_input : BlackInput ,
98
+ python_setup : PythonSetup ,
99
+ subprocess_encoding_environment : SubprocessEncodingEnvironment ,
100
+ * ,
101
+ check_only : bool ,
102
+ ):
103
+ target = wrapped_target .target
104
+ pex_args = _generate_black_pex_args (target .sources .snapshot .files , black_input .config_path , check_only = check_only )
105
+
106
+ request = black_input .resolved_requirements_pex .create_execute_request (
79
107
python_setup = python_setup ,
80
108
subprocess_encoding_environment = subprocess_encoding_environment ,
81
109
pex_path = "./black.pex" ,
82
110
pex_args = pex_args ,
83
- input_files = merged_input_files ,
111
+ input_files = black_input . merged_input_files ,
84
112
output_files = target .sources .snapshot .files ,
85
113
description = f'Run Black for { target .address .reference ()} ' ,
86
114
)
115
+ return request
116
+
117
+
118
+ @rule
119
+ def fmt_with_black (
120
+ wrapped_target : FormattablePythonTarget ,
121
+ black_input : BlackInput ,
122
+ python_setup : PythonSetup ,
123
+ subprocess_encoding_environment : SubprocessEncodingEnvironment ,
124
+ ) -> FmtResult :
125
+
126
+ request = _generate_black_request (wrapped_target , black_input , python_setup , subprocess_encoding_environment , check_only = False )
87
127
88
128
result = yield Get (ExecuteProcessResult , ExecuteProcessRequest , request )
89
129
@@ -94,6 +134,25 @@ def run_black(
94
134
)
95
135
96
136
137
+ @rule
138
+ def lint_with_black (
139
+ wrapped_target : FormattablePythonTarget ,
140
+ black_input : BlackInput ,
141
+ python_setup : PythonSetup ,
142
+ subprocess_encoding_environment : SubprocessEncodingEnvironment ,
143
+ ) -> LintResult :
144
+
145
+ request = _generate_black_request (wrapped_target , black_input , python_setup , subprocess_encoding_environment , check_only = True )
146
+
147
+ result = yield Get (FallibleExecuteProcessResult , ExecuteProcessRequest , request )
148
+
149
+ yield LintResult (
150
+ exit_code = result .exit_code ,
151
+ stdout = result .stdout .decode (),
152
+ stderr = result .stderr .decode (),
153
+ )
154
+
155
+
97
156
# TODO: remove this workaround once https://github.com/pantsbuild/pants/issues/8343 is addressed
98
157
@rule
99
158
def target_adaptor (target : PythonTargetAdaptor ) -> FormattablePythonTarget :
@@ -131,12 +190,14 @@ def rules():
131
190
binary_adaptor ,
132
191
tests_adaptor ,
133
192
plugin_adaptor ,
134
- run_black ,
135
- UnionRule (FmtTarget , PythonTargetAdaptor ),
136
- UnionRule (FmtTarget , PythonAppAdaptor ),
137
- UnionRule (FmtTarget , PythonBinaryAdaptor ),
138
- UnionRule (FmtTarget , PythonTestsAdaptor ),
139
- UnionRule (FmtTarget , PantsPluginAdaptor ),
193
+ get_black_input ,
194
+ fmt_with_black ,
195
+ lint_with_black ,
196
+ UnionRule (TargetWithSources , PythonTargetAdaptor ),
197
+ UnionRule (TargetWithSources , PythonAppAdaptor ),
198
+ UnionRule (TargetWithSources , PythonBinaryAdaptor ),
199
+ UnionRule (TargetWithSources , PythonTestsAdaptor ),
200
+ UnionRule (TargetWithSources , PantsPluginAdaptor ),
140
201
optionable_rule (Black ),
141
202
optionable_rule (PythonSetup ),
142
203
]
0 commit comments