7
7
import subprocess
8
8
import contextlib
9
9
10
- from dataclasses import dataclass , fields
11
- from dataclasses import field as dataclass_field
10
+ from dataclasses import dataclass
12
11
13
12
14
13
GIT_ROOT = pathlib .Path (
19
18
20
19
21
20
def clang_format (clang_format , config , files ):
21
+ if not files :
22
+ raise ValueError ("Files list cannot be empty" )
23
+
22
24
cmd = [clang_format , "--verbose" , f"--style=file:{ config .as_posix ()} " , "-i" ]
23
25
cmd .extend (files )
24
26
25
27
subprocess .run (cmd , check = True )
26
28
27
29
30
+ def ls_files (patterns ):
31
+ """Git-only search, but rather poor at matching complex patterns (at least w/ <=py3.12)"""
32
+ proc = subprocess .run (
33
+ ["git" , "--no-pager" , "ls-files" ],
34
+ capture_output = True ,
35
+ check = True ,
36
+ universal_newlines = True ,
37
+ )
38
+
39
+ out = []
40
+ for line in proc .stdout .split ("\n " ):
41
+ path = pathlib .Path (line .strip ())
42
+ if any (path .match (pattern ) for pattern in patterns ):
43
+ out .append (path )
44
+
45
+ return out
46
+
47
+
28
48
def find_files (patterns ):
49
+ """Filesystem search, matches both git and non-git files"""
29
50
return [
30
51
file
31
52
for pattern in patterns
32
53
for file in [found for found in GIT_ROOT .rglob (pattern )]
33
54
]
34
55
35
56
36
- # just like original script, only handle a subset of core sources
37
57
def find_core_files ():
58
+ """Returns a subset of Core files that should be formatted"""
38
59
return [
39
60
file
40
61
for file in find_files (
@@ -54,27 +75,19 @@ def find_core_files():
54
75
if file .is_file ()
55
76
and file .suffix in (".c" , ".cpp" , ".h" , ".hpp" )
56
77
and not GIT_ROOT / "tests/host/bin" in file .parents
57
- and not "ArduinoCatch" in file .name
58
- and not "catch.hpp" in file .name
78
+ and not GIT_ROOT / "tests/host/common/catch.hpp" == file
59
79
]
60
80
61
81
62
- # include *every* .ino file, excluding submodules
63
82
def find_arduino_files ():
64
- all_libraries = [path for path in GIT_ROOT .glob ("libraries/*" ) if path .is_dir ()]
65
- submodules = [
66
- path .parent for path in GIT_ROOT .glob ("libraries/*/.git" ) if path .is_file ()
83
+ """Returns every .ino file available in the repository, excluding submodule ones"""
84
+ return [
85
+ ino
86
+ for library in find_files (("libraries/*" ,))
87
+ if library .is_dir () and not (library / ".git" ).exists ()
88
+ for ino in library .rglob ("**/*.ino" )
67
89
]
68
90
69
- libraries = [library for library in all_libraries if not library in submodules ]
70
-
71
- files = []
72
- for library in libraries :
73
- for ino in library .rglob ("**/*.ino" ):
74
- files .append (ino )
75
-
76
- return files
77
-
78
91
79
92
FILES_PRESETS = {
80
93
"core" : find_core_files ,
@@ -89,52 +102,51 @@ class Changed:
89
102
lines : list [int ]
90
103
91
104
92
- @dataclass
93
105
class Context :
94
- append_hunk : bool = False
95
- deleted : bool = False
96
- file : str = ""
97
- hunk : list [str ] = dataclass_field (default_factory = list )
98
- markers : list [str ] = dataclass_field (default_factory = list )
106
+ def __init__ (self ):
107
+ self .append_hunk = False
108
+ self .deleted = False
109
+ self .file = ""
110
+ self .hunk = []
111
+ self .markers = []
112
+
113
+ def reset (self ):
114
+ self .__init__ ()
115
+
116
+ def reset_with_line (self , line ):
117
+ self .reset ()
118
+ self .hunk .append (line )
119
+
120
+ def pop (self , out , line ):
121
+ if self .file and self .hunk and self .markers :
122
+ out .append (
123
+ Changed (file = self .file , hunk = "\n " .join (self .hunk ), lines = self .markers )
124
+ )
125
+
126
+ self .reset_with_line (line )
99
127
100
128
101
- # naive git-diff parser for clang-format aftercare
102
- # ref. https://github.com/cpp-linter/cpp-linter/blob/main/cpp_linter/git/__init__.py ::parse_diff
103
- # ref. https://github.com/libgit2/pygit2/blob/master/src/diff.c ::parse_diff
104
- # TODO: pygit2?
105
129
def changed_files ():
130
+ """
131
+ Naive git-diff output parser. Generates list[Changed] for every file changed after clang-format.
132
+ """
106
133
proc = subprocess .run (
107
134
["git" , "--no-pager" , "diff" ],
108
135
capture_output = True ,
109
136
check = True ,
110
137
universal_newlines = True ,
111
138
)
112
139
113
- def reset_context (ctx ):
114
- other = Context ()
115
- for field in fields (other ):
116
- setattr (ctx , field .name , getattr (other , field .name ))
117
-
118
- def reset_with_line (ctx , line ):
119
- reset_context (ctx )
120
- if line :
121
- ctx .hunk = [line ]
122
-
123
- def pop (out , context , line ):
124
- if ctx .file and ctx .hunk and ctx .markers :
125
- out .append (
126
- Changed (file = ctx .file , hunk = "\n " .join (ctx .hunk ), lines = ctx .markers )
127
- )
128
-
129
- reset_with_line (context , line )
130
-
131
- out = []
132
140
ctx = Context ()
141
+ out = []
133
142
143
+ # TODO: pygit2?
144
+ # ref. https://github.com/cpp-linter/cpp-linter/blob/main/cpp_linter/git/__init__.py ::parse_diff
145
+ # ref. https://github.com/libgit2/pygit2/blob/master/src/diff.c ::parse_diff
134
146
for line in proc .stdout .split ("\n " ):
135
147
# '--- a/path/to/changed/file' most likely
136
148
if line .startswith ("---" ):
137
- pop (out , ctx , line )
149
+ ctx . pop (out , line )
138
150
139
151
# '+++ b/path/to/changed/file' most likely
140
152
# '+++ /dev/null' aka removed file
@@ -145,8 +157,6 @@ def pop(out, context, line):
145
157
deleted = "/dev/null" in file
146
158
if not deleted :
147
159
ctx .file = file [2 :]
148
- else :
149
- ctx .file = file
150
160
151
161
# @@ from-file-line-numbers to-file-line-numbers @@
152
162
elif not ctx .deleted and line .startswith ("@@" ):
@@ -166,7 +176,7 @@ def pop(out, context, line):
166
176
elif ctx .append_hunk and line .startswith (("+" , "-" , " " )):
167
177
ctx .hunk .append (line )
168
178
169
- pop (out , ctx , line )
179
+ ctx . pop (out , line )
170
180
171
181
return out
172
182
@@ -223,8 +233,9 @@ def run_assert(args):
223
233
if args .with_summary :
224
234
summary_diff (changed )
225
235
226
- if not args .with_summary :
236
+ if args .with_diff :
227
237
stdout_diff ()
238
+
228
239
assert_unchanged ()
229
240
230
241
@@ -249,8 +260,9 @@ def run_assert(args):
249
260
250
261
assert_ = cmd .add_parser ("assert" )
251
262
assert_ .set_defaults (func = run_assert )
252
- assert_ .add_argument ("--with-summary " , action = "store_true" )
263
+ assert_ .add_argument ("--with-diff " , action = "store_true" )
253
264
assert_ .add_argument ("--with-errors" , action = "store_true" )
265
+ assert_ .add_argument ("--with-summary" , action = "store_true" )
254
266
255
267
args = parser .parse_args ()
256
268
args .func (args )
0 commit comments