get_maintainer.py: process patches individually
When given the -m/-merge-check option, get_maintainer.py parses the
Acked-by and Reviewed-by tags that may be found in a patchset or
Github PR. In presence of several patches the tags should apply to
each patch individually, not to the whole patchset as is currently
done. As a result, the script may fail to report some unapproved
changes.
Fix this issue by splitting patchsets into individual patches before
processing.
Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
diff --git a/scripts/get_maintainer.py b/scripts/get_maintainer.py
index 72cbeea..645db61 100755
--- a/scripts/get_maintainer.py
+++ b/scripts/get_maintainer.py
@@ -17,6 +17,7 @@
DIFF_GIT_RE = re.compile(r'^diff --git a/(?P<path>.*) ')
REVIEWED_RE = re.compile(r'^Reviewed-by: (?P<approver>.*>)')
ACKED_RE = re.compile(r'^Acked-by: (?P<approver>.*>)')
+PATCH_START = re.compile(r'^From [0-9a-f]{40}')
def get_args():
@@ -88,9 +89,41 @@
return subsystems
+# If @patchset is a patchset files and contains 2 patches or more, write
+# individual patches to temporary files and return the paths.
+# Otherwise return [].
+def split_patchset(patchset):
+ psname = os.path.basename(patchset).replace('.', '_')
+ patchnum = 0
+ of = None
+ ret = []
+ f = None
+ try:
+ f = open(patchset, "r")
+ except OsError:
+ return []
+ for line in f:
+ match = re.search(PATCH_START, line)
+ if match:
+ # New patch found: create new file
+ patchnum += 1
+ prefix = "{}_{}_".format(patchnum, psname)
+ of = tempfile.NamedTemporaryFile(mode="w", prefix=prefix,
+ suffix=".patch",
+ delete=False)
+ ret.append(of.name)
+ if of:
+ of.write(line)
+ if len(ret) >= 2:
+ return ret
+ if len(ret) == 1:
+ os.remove(ret[0])
+ return []
+
+
# If @path is a patch file, returns the paths touched by the patch as well
# as the content of the review/ack tags
-def get_paths_from_patchset(patch):
+def get_paths_from_patch(patch):
paths = []
approvers = []
try:
@@ -197,17 +230,27 @@
args = get_args()
all_subsystems = parse_maintainers()
paths = []
+ arglist = []
downloads = []
+ split_patches = []
for pr in args.github_pr or []:
downloads += [download(pr)]
for arg in args.arg + downloads:
+ if os.path.exists(arg):
+ patches = split_patchset(arg)
+ if patches:
+ split_patches += patches
+ continue
+ arglist.append(arg)
+
+ for arg in arglist + split_patches:
patch_paths = []
approved_by = []
if os.path.exists(arg):
- # Try to parse as a patch or patch set
- (patch_paths, approved_by) = get_paths_from_patchset(arg)
+ # Try to parse as a patch
+ (patch_paths, approved_by) = get_paths_from_patch(arg)
if not patch_paths:
# Not a patch, consider the path itself
# as_posix() cleans the path a little bit (suppress leading ./ and
@@ -225,7 +268,7 @@
if not approved:
paths += [path]
- for f in downloads:
+ for f in downloads + split_patches:
os.remove(f)
if args.file: