Add a new script GetMaintainer.py that uses the new Maintainer.txt format
to determine which addresses to cc on patch submission.
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daude <philmd@redhat.com>
---
BaseTools/Scripts/GetMaintainer.py | 190 +++++++++++++++++++++++++++++
1 file changed, 190 insertions(+)
create mode 100644 BaseTools/Scripts/GetMaintainer.py
diff --git a/BaseTools/Scripts/GetMaintainer.py b/BaseTools/Scripts/GetMaintainer.py
new file mode 100644
index 000000000000..fbc63522db77
--- /dev/null
+++ b/BaseTools/Scripts/GetMaintainer.py
@@ -0,0 +1,190 @@
+## @file
+# Retrieves the people to request review from on submission of a commit.
+#
+# Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+from __future__ import print_function
+from collections import defaultdict
+from collections import OrderedDict
+import argparse
+import os
+import re
+import SetupGit
+
+EXPRESSIONS = {
+ 'exclude': re.compile(r'^X:\s*(?P<exclude>.*?)\r*$'),
+ 'file': re.compile(r'^F:\s*(?P<file>.*?)\r*$'),
+ 'list': re.compile(r'^L:\s*(?P<list>.*?)\r*$'),
+ 'maintainer': re.compile(r'^M:\s*(?P<maintainer>.*<.*?>)\r*$'),
+ 'reviewer': re.compile(r'^R:\s*(?P<reviewer>.*?)\r*$'),
+ 'status': re.compile(r'^S:\s*(?P<status>.*?)\r*$'),
+ 'tree': re.compile(r'^T:\s*(?P<tree>.*?)\r*$'),
+ 'webpage': re.compile(r'^W:\s*(?P<webpage>.*?)\r*$')
+}
+
+def printsection(section):
+ """Prints out the dictionary describing a Maintainers.txt section."""
+ print('===')
+ for key in section.keys():
+ print("Key: %s" % key)
+ for item in section[key]:
+ print(' %s' % item)
+
+def pattern_to_regex(pattern):
+ """Takes a string containing regular UNIX path wildcards
+ and returns a string suitable for matching with regex."""
+
+ pattern = pattern.replace('.', r'\.')
+ pattern = pattern.replace('?', r'.')
+ pattern = pattern.replace('*', r'.*')
+
+ if pattern.endswith('/'):
+ pattern += r'.*'
+ elif pattern.endswith('.*'):
+ pattern = pattern[:-2]
+ pattern += r'(?!.*?/.*?)'
+
+ return pattern
+
+def path_in_section(path, section):
+ """Returns True of False indicating whether the path is covered by
+ the current section."""
+ if not 'file' in section:
+ return False
+
+ for pattern in section['file']:
+ regex = pattern_to_regex(pattern)
+
+ match = re.match(regex, path)
+ if match:
+ # Check if there is an exclude pattern that applies
+ for pattern in section['exclude']:
+ regex = pattern_to_regex(pattern)
+
+ match = re.match(regex, path)
+ if match:
+ return False
+
+ return True
+
+ return False
+
+def get_section_maintainers(path, section):
+ """Returns a list with email addresses to any M: and R: entries
+ matching the provided path in the provided section."""
+ maintainers = []
+ lists = []
+
+ if path_in_section(path, section):
+ for address in section['maintainer'], section['reviewer']:
+ # Convert to list if necessary
+ if isinstance(address, list):
+ maintainers += address
+ else:
+ lists += [address]
+ for address in section['list']:
+ # Convert to list if necessary
+ if isinstance(address, list):
+ lists += address
+ else:
+ lists += [address]
+
+ return maintainers, lists
+
+def get_maintainers(path, sections, level=0):
+ """For 'path', iterates over all sections, returning maintainers
+ for matching ones."""
+ maintainers = []
+ lists = []
+ for section in sections:
+ tmp_maint, tmp_lists = get_section_maintainers(path, section)
+ if tmp_maint:
+ maintainers += tmp_maint
+ if tmp_lists:
+ lists += tmp_lists
+
+ if not maintainers:
+ # If no match found, look for match for (nonexistent) file
+ # REPO.working_dir/<default>
+ print('"%s": no maintainers found, looking for default' % path)
+ if level == 0:
+ maintainers = get_maintainers('<default>', sections, level=level + 1)
+ else:
+ print("No <default> maintainers set for project.")
+ if not maintainers:
+ return None
+
+ return maintainers + lists
+
+def parse_maintainers_line(line):
+ """Parse one line of Maintainers.txt, returning any match group and its key."""
+ for key, expression in EXPRESSIONS.items():
+ match = expression.match(line)
+ if match:
+ return key, match.group(key)
+ return None, None
+
+def parse_maintainers_file(filename):
+ """Parse the Maintainers.txt from top-level of repo and
+ return a list containing dictionaries of all sections."""
+ with open(filename, 'r') as text:
+ line = text.readline()
+ sectionlist = []
+ section = defaultdict(list)
+ while line:
+ key, value = parse_maintainers_line(line)
+ if key and value:
+ section[key].append(value)
+
+ line = text.readline()
+ # If end of section (end of file, or non-tag line encountered)...
+ if not key or not value or not line:
+ # ...if non-empty, append section to list.
+ if section:
+ sectionlist.append(section.copy())
+ section.clear()
+
+ return sectionlist
+
+def get_modified_files(repo, args):
+ """Returns a list of the files modified by the commit specified in 'args'."""
+ commit = repo.commit(args.commit)
+ return commit.stats.files
+
+if __name__ == '__main__':
+ PARSER = argparse.ArgumentParser(
+ description='Retrieves information on who to cc for review on a given commit')
+ PARSER.add_argument('commit',
+ action="store",
+ help='git revision to examine (default: HEAD)',
+ nargs='?',
+ default='HEAD')
+ PARSER.add_argument('-l', '--lookup',
+ help='Find section matches for path LOOKUP',
+ required=False)
+ ARGS = PARSER.parse_args()
+
+ REPO = SetupGit.locate_repo()
+
+ CONFIG_FILE = os.path.join(REPO.working_dir, 'Maintainers.txt')
+
+ SECTIONS = parse_maintainers_file(CONFIG_FILE)
+
+ if ARGS.lookup:
+ FILES = [ARGS.lookup]
+ else:
+ FILES = get_modified_files(REPO, ARGS)
+
+ ADDRESSES = []
+
+ for file in FILES:
+ print(file)
+ addresslist = get_maintainers(file, SECTIONS)
+ if addresslist:
+ ADDRESSES += addresslist
+
+ for address in list(OrderedDict.fromkeys(ADDRESSES)):
+ print(' %s' % address)
--
2.20.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#43666): https://edk2.groups.io/g/devel/message/43666
Mute This Topic: https://groups.io/mt/32444053/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
On 07/12/19 19:01, Leif Lindholm wrote: > Add a new script GetMaintainer.py that uses the new Maintainer.txt format > to determine which addresses to cc on patch submission. > > Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> > Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> > Tested-by: Philippe Mathieu-Daude <philmd@redhat.com> > --- > BaseTools/Scripts/GetMaintainer.py | 190 +++++++++++++++++++++++++++++ > 1 file changed, 190 insertions(+) > create mode 100644 BaseTools/Scripts/GetMaintainer.py I should really re-review this from zero, but it's 0:55 AM again. :/ Anyway, I think this script is a good candidate for gradual improvements (should such ever become necessary, that is). The script doesn't have to be perfect to be incredibly useful. Acked-by: Laszlo Ersek <lersek@redhat.com> ... Did you have me in mind for the ArmVirtPkg and OvmfPkg pathname patterns, for replacing the natural language pointers? :) Thanks! Laszlo -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#43679): https://edk2.groups.io/g/devel/message/43679 Mute This Topic: https://groups.io/mt/32444053/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
On Sat, Jul 13, 2019 at 12:58:18AM +0200, Laszlo Ersek wrote: > On 07/12/19 19:01, Leif Lindholm wrote: > > Add a new script GetMaintainer.py that uses the new Maintainer.txt format > > to determine which addresses to cc on patch submission. > > > > Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> > > Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> > > Tested-by: Philippe Mathieu-Daude <philmd@redhat.com> > > --- > > BaseTools/Scripts/GetMaintainer.py | 190 +++++++++++++++++++++++++++++ > > 1 file changed, 190 insertions(+) > > create mode 100644 BaseTools/Scripts/GetMaintainer.py > > I should really re-review this from zero, but it's 0:55 AM again. :/ > > Anyway, I think this script is a good candidate for gradual improvements > (should such ever become necessary, that is). The script doesn't have to > be perfect to be incredibly useful. > > Acked-by: Laszlo Ersek <lersek@redhat.com> Thanks! > ... Did you have me in mind for the ArmVirtPkg and OvmfPkg pathname > patterns, for replacing the natural language pointers? :) That would be ideal, thanks. I might miss something if I did it. I would be happy to push them together with 1-2/3 once ready. Best Regards, Leif -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#43696): https://edk2.groups.io/g/devel/message/43696 Mute This Topic: https://groups.io/mt/32444053/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
On 07/13/19 12:41, Leif Lindholm wrote: > On Sat, Jul 13, 2019 at 12:58:18AM +0200, Laszlo Ersek wrote: >> On 07/12/19 19:01, Leif Lindholm wrote: >>> Add a new script GetMaintainer.py that uses the new Maintainer.txt format >>> to determine which addresses to cc on patch submission. >>> >>> Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> >>> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> >>> Tested-by: Philippe Mathieu-Daude <philmd@redhat.com> >>> --- >>> BaseTools/Scripts/GetMaintainer.py | 190 +++++++++++++++++++++++++++++ >>> 1 file changed, 190 insertions(+) >>> create mode 100644 BaseTools/Scripts/GetMaintainer.py >> >> I should really re-review this from zero, but it's 0:55 AM again. :/ >> >> Anyway, I think this script is a good candidate for gradual improvements >> (should such ever become necessary, that is). The script doesn't have to >> be perfect to be incredibly useful. >> >> Acked-by: Laszlo Ersek <lersek@redhat.com> > > Thanks! > >> ... Did you have me in mind for the ArmVirtPkg and OvmfPkg pathname >> patterns, for replacing the natural language pointers? :) > > That would be ideal, thanks. I might miss something if I did it. > I would be happy to push them together with 1-2/3 once ready. Posted: [edk2-devel] [PATCH 0/4] Maintainers.txt: formalize ArmVirtPkg and OvmfPkg subsystem pathnames https://edk2.groups.io/g/devel/message/43728 http://mid.mail-archive.com/20190715170431.13955-1-lersek@redhat.com (The mail-archive.com link will start working after mail-archive.com indexes the message. Oh, the beauty of stable message identifiers! :) ) Thanks Laszlo -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#43735): https://edk2.groups.io/g/devel/message/43735 Mute This Topic: https://groups.io/mt/32444053/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2026 Red Hat, Inc.