forked from linux-netdev/nipa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtree_match.py
184 lines (155 loc) · 4.93 KB
/
tree_match.py
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2019 Netronome Systems, Inc.
# TODO: document
import re
from core import log, log_open_sec, log_end_sec
def series_tree_name_direct(series):
for t in ['net-next', 'bpf-next', 'net', 'bpf']:
if re.match(r'\[.*{pfx}.*\]'.format(pfx=t), series.subject):
return t
def _file_name_match_start(pfx, fn):
return fn.startswith(pfx)
def _file_name_match_dotted(pfx, fn):
dirs = pfx.split('/')
while True:
dirs.pop(0)
dotted = '.../' + '/'.join(dirs)
if dotted == '.../':
return False
if fn.startswith(dotted):
return True
def _tree_name_should_be_local_files(raw_email):
"""
Returns True: patch should have been explicitly designated for local tree
False: patch has nothing to do with local trees
None: patch has mixed contents, it touches local code, but also code outside
"""
acceptable_files = {
'.../',
'CREDITS',
'MAINTAINERS',
'Documentation/',
'include/',
'rust/',
'tools/',
'drivers/vhost/',
}
required_files = {
'Documentation/networking/',
'include/linux/netdevice.h',
'include/linux/skbuff.h',
'include/net/',
'include/phy/',
'net/',
'drivers/atm/',
'drivers/dpll/',
'drivers/isdn/',
'drivers/net/',
'drivers/dsa/',
'drivers/nfc/',
'drivers/phy/',
'drivers/ptp/',
'drivers/net/ethernet/',
'kernel/bpf/',
'tools/net/',
'tools/testing/selftests/net/',
}
excluded_files = {
'drivers/net/wireless/',
}
all_files = acceptable_files.union(required_files)
required_found = False
foreign_found = False
lines = raw_email.split('\n')
r_diffstat = re.compile(r'^\s*([-\w/._]+)\s+\|\s+\d+\s*[-+]*\s*$')
r_header = re.compile(r'\+\+\+ b/([-\w/._]+)$')
for line in lines:
match = r_header.match(line)
if not match:
match = r_diffstat.match(line)
if not match:
continue
found = False
excluded = False
file_name = match.group(1)
log_open_sec(f'Checking file name {file_name}')
if file_name.startswith('.../'):
compare = _file_name_match_dotted
else:
compare = _file_name_match_start
for fn in excluded_files:
excluded = excluded or compare(fn, file_name)
if excluded:
log(f'Excluded by {fn}', "")
break
for fn in all_files:
matches = compare(fn, file_name)
if not matches:
continue
log(f'Matched by {fn}', "")
found = True
if not excluded:
required_found = required_found or fn in required_files
log_end_sec()
if not found:
log(f'File name {file_name} was not matched by any list', "")
foreign_found = True
log(f'Required found: {required_found}, foreign_found: {foreign_found}', "")
if not required_found:
return False
if foreign_found:
return None
return True
def _tree_name_should_be_local(raw_email):
return _tree_name_should_be_local_files(raw_email)
def series_tree_name_should_be_local(series):
all_local = True
some_local = False
for p in series.patches:
ret = _tree_name_should_be_local(p.raw_patch)
# Returns tri-state True, None, False. And works well:
# True and None -> None
# True and False -> False
# False and None -> False
all_local = all_local and ret
# True or None -> True
# True or False -> True
# False or None -> False
some_local = some_local or ret
return all_local, some_local
def _ignore_missing_tree_name(subject):
log(f'checking ignore for {subject}', "")
return subject.count('] can: ') != 0 or \
subject.count('pull-request:') != 0 or \
subject.count('[GIT.*]')
def series_ignore_missing_tree_name(series):
if series.cover_letter:
return _ignore_missing_tree_name(series.subject)
for p in series.patches:
if not _ignore_missing_tree_name(p.subject):
return False
return True
def series_is_a_fix_for(s, tree):
commits = []
regex = re.compile(r'^Fixes: [a-f0-9]* \(')
for p in s.patches:
commits += regex.findall(p.raw_patch)
for c in commits:
if not tree.contains(c):
return False
return commits and tree.check_applies(s)
def series_needs_async(s) -> bool:
bad_files = {
'net/sock.h',
'net/tcp.h',
'linux/bpf.h',
'linux/netdevice.h',
'linux/sock',
'linux/tcp.h'
}
for p in s.patches:
for needle in bad_files:
if p.raw_patch.find(needle) > 0:
return True
return False