-## @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 = []
+## @file\r
+# Retrieves the people to request review from on submission of a commit.\r
+#\r
+# Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+\r
+from __future__ import print_function\r
+from collections import defaultdict\r
+from collections import OrderedDict\r
+import argparse\r
+import os\r
+import re\r
+import SetupGit\r
+\r
+EXPRESSIONS = {\r
+ 'exclude': re.compile(r'^X:\s*(?P<exclude>.*?)\r*$'),\r
+ 'file': re.compile(r'^F:\s*(?P<file>.*?)\r*$'),\r
+ 'list': re.compile(r'^L:\s*(?P<list>.*?)\r*$'),\r
+ 'maintainer': re.compile(r'^M:\s*(?P<maintainer>.*<.*?>)\r*$'),\r
+ 'reviewer': re.compile(r'^R:\s*(?P<reviewer>.*?)\r*$'),\r
+ 'status': re.compile(r'^S:\s*(?P<status>.*?)\r*$'),\r
+ 'tree': re.compile(r'^T:\s*(?P<tree>.*?)\r*$'),\r
+ 'webpage': re.compile(r'^W:\s*(?P<webpage>.*?)\r*$')\r
+}\r
+\r
+def printsection(section):\r
+ """Prints out the dictionary describing a Maintainers.txt section."""\r
+ print('===')\r
+ for key in section.keys():\r
+ print("Key: %s" % key)\r
+ for item in section[key]:\r
+ print(' %s' % item)\r
+\r
+def pattern_to_regex(pattern):\r
+ """Takes a string containing regular UNIX path wildcards\r
+ and returns a string suitable for matching with regex."""\r
+\r
+ pattern = pattern.replace('.', r'\.')\r
+ pattern = pattern.replace('?', r'.')\r
+ pattern = pattern.replace('*', r'.*')\r
+\r
+ if pattern.endswith('/'):\r
+ pattern += r'.*'\r
+ elif pattern.endswith('.*'):\r
+ pattern = pattern[:-2]\r
+ pattern += r'(?!.*?/.*?)'\r
+\r
+ return pattern\r
+\r
+def path_in_section(path, section):\r
+ """Returns True of False indicating whether the path is covered by\r
+ the current section."""\r
+ if not 'file' in section:\r
+ return False\r
+\r
+ for pattern in section['file']:\r
+ regex = pattern_to_regex(pattern)\r
+\r
+ match = re.match(regex, path)\r
+ if match:\r
+ # Check if there is an exclude pattern that applies\r
+ for pattern in section['exclude']:\r
+ regex = pattern_to_regex(pattern)\r
+\r
+ match = re.match(regex, path)\r
+ if match:\r
+ return False\r
+\r
+ return True\r
+\r
+ return False\r
+\r
+def get_section_maintainers(path, section):\r
+ """Returns a list with email addresses to any M: and R: entries\r
+ matching the provided path in the provided section."""\r
+ maintainers = []\r
+ lists = []\r
nowarn_status = ['Supported', 'Maintained']\r
-
- if path_in_section(path, section):
+\r
+ if path_in_section(path, section):\r
for status in section['status']:\r
if status not in nowarn_status:\r
print('WARNING: Maintained status for "%s" is \'%s\'!' % (path, status))\r
- 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)
+ for address in section['maintainer'], section['reviewer']:\r
+ # Convert to list if necessary\r
+ if isinstance(address, list):\r
+ maintainers += address\r
+ else:\r
+ lists += [address]\r
+ for address in section['list']:\r
+ # Convert to list if necessary\r
+ if isinstance(address, list):\r
+ lists += address\r
+ else:\r
+ lists += [address]\r
+\r
+ return maintainers, lists\r
+\r
+def get_maintainers(path, sections, level=0):\r
+ """For 'path', iterates over all sections, returning maintainers\r
+ for matching ones."""\r
+ maintainers = []\r
+ lists = []\r
+ for section in sections:\r
+ tmp_maint, tmp_lists = get_section_maintainers(path, section)\r
+ if tmp_maint:\r
+ maintainers += tmp_maint\r
+ if tmp_lists:\r
+ lists += tmp_lists\r
+\r
+ if not maintainers:\r
+ # If no match found, look for match for (nonexistent) file\r
+ # REPO.working_dir/<default>\r
+ print('"%s": no maintainers found, looking for default' % path)\r
+ if level == 0:\r
+ maintainers = get_maintainers('<default>', sections, level=level + 1)\r
+ else:\r
+ print("No <default> maintainers set for project.")\r
+ if not maintainers:\r
+ return None\r
+\r
+ return maintainers + lists\r
+\r
+def parse_maintainers_line(line):\r
+ """Parse one line of Maintainers.txt, returning any match group and its key."""\r
+ for key, expression in EXPRESSIONS.items():\r
+ match = expression.match(line)\r
+ if match:\r
+ return key, match.group(key)\r
+ return None, None\r
+\r
+def parse_maintainers_file(filename):\r
+ """Parse the Maintainers.txt from top-level of repo and\r
+ return a list containing dictionaries of all sections."""\r
+ with open(filename, 'r') as text:\r
+ line = text.readline()\r
+ sectionlist = []\r
+ section = defaultdict(list)\r
+ while line:\r
+ key, value = parse_maintainers_line(line)\r
+ if key and value:\r
+ section[key].append(value)\r
+\r
+ line = text.readline()\r
+ # If end of section (end of file, or non-tag line encountered)...\r
+ if not key or not value or not line:\r
+ # ...if non-empty, append section to list.\r
+ if section:\r
+ sectionlist.append(section.copy())\r
+ section.clear()\r
+\r
+ return sectionlist\r
+\r
+def get_modified_files(repo, args):\r
+ """Returns a list of the files modified by the commit specified in 'args'."""\r
+ commit = repo.commit(args.commit)\r
+ return commit.stats.files\r
+\r
+if __name__ == '__main__':\r
+ PARSER = argparse.ArgumentParser(\r
+ description='Retrieves information on who to cc for review on a given commit')\r
+ PARSER.add_argument('commit',\r
+ action="store",\r
+ help='git revision to examine (default: HEAD)',\r
+ nargs='?',\r
+ default='HEAD')\r
+ PARSER.add_argument('-l', '--lookup',\r
+ help='Find section matches for path LOOKUP',\r
+ required=False)\r
+ ARGS = PARSER.parse_args()\r
+\r
+ REPO = SetupGit.locate_repo()\r
+\r
+ CONFIG_FILE = os.path.join(REPO.working_dir, 'Maintainers.txt')\r
+\r
+ SECTIONS = parse_maintainers_file(CONFIG_FILE)\r
+\r
+ if ARGS.lookup:\r
+ FILES = [ARGS.lookup]\r
+ else:\r
+ FILES = get_modified_files(REPO, ARGS)\r
+\r
+ ADDRESSES = []\r
+\r
+ for file in FILES:\r
+ print(file)\r
+ addresslist = get_maintainers(file, SECTIONS)\r
+ if addresslist:\r
+ ADDRESSES += addresslist\r
+\r
+ for address in list(OrderedDict.fromkeys(ADDRESSES)):\r
+ print(' %s' % address)\r