From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by mx.groups.io with SMTP id smtpd.web08.5035.1625792906163963637 for ; Thu, 08 Jul 2021 18:08:26 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@intel.onmicrosoft.com header.s=selector2-intel-onmicrosoft-com header.b=BXZbn+ls; spf=pass (domain: intel.com, ip: 134.134.136.20, mailfrom: bob.c.feng@intel.com) X-IronPort-AV: E=McAfee;i="6200,9189,10039"; a="196801116" X-IronPort-AV: E=Sophos;i="5.84,225,1620716400"; d="scan'208";a="196801116" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jul 2021 18:08:25 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,225,1620716400"; d="scan'208";a="487865529" Received: from orsmsx605.amr.corp.intel.com ([10.22.229.18]) by FMSMGA003.fm.intel.com with ESMTP; 08 Jul 2021 18:08:24 -0700 Received: from orsmsx608.amr.corp.intel.com (10.22.229.21) by ORSMSX605.amr.corp.intel.com (10.22.229.18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2242.4; Thu, 8 Jul 2021 18:08:23 -0700 Received: from orsmsx603.amr.corp.intel.com (10.22.229.16) by ORSMSX608.amr.corp.intel.com (10.22.229.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2242.10; Thu, 8 Jul 2021 18:08:23 -0700 Received: from orsedg603.ED.cps.intel.com (10.7.248.4) by orsmsx603.amr.corp.intel.com (10.22.229.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2242.10 via Frontend Transport; Thu, 8 Jul 2021 18:08:23 -0700 Received: from NAM12-MW2-obe.outbound.protection.outlook.com (104.47.66.46) by edgegateway.intel.com (134.134.137.100) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2242.4; Thu, 8 Jul 2021 18:08:23 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dHpFgQG+fo3L6DsXt12BaJHReLLG1MsmGZ1vwkAjGCJBOjXbTK2KRGzjouZJUHsJIfdT/BGug4EE3rWrg6O17bTOAjcwTfAPkJfc9lV997KGgIY4Mx3yhl6X8fNsTGacDIk70dIKulSf74fecsTUdT9HTCpVoM/d1UFnxJXt6nrI6UkUFDg5y1PlAC0ck5gOVkAHQrn51YZ7qq85VgYWuagAIBRdmybcl9M9/870sFiLwlmfmf+xk7WbqWbFQAZSnGP70CHW5fscKpuz+ixefzm+aWRZeCbfp2124NspDLcVWuq2m7ArpkdW6dkFj2idYnmsL21oAjl5AHD6NCvrvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=RAZtUimKsbcV2e6YEMNqMX+tekhoicVvriaCHEg/VWk=; b=QV7j1xPO+G8HhC8yfMNWMzVWpH67S7FdzGpbm9abwa1oEOjPk0wwz7bq6eLI157YCem8RkRaVy8ozP2/HBHdnaQuVxosG34h3DIN2YQC3RUGMyzAYTgSZfQoP46WR5KRxbCwj/rHrd3ZfQkKRi7uourqzwvHe61pkxeNJf04u6iC5cLhuTx2mBTJsrUSiVIII5o0bTsVcMkEDCACaTt+tC3OQ5Ucj/hEzxB1/fzh5OSc4xSv5C9JLyfq8O/RA4g9W57SDPLoOjE7W0HyE097UWfx/OkgiM85ugEigo8svki+0qSO7aM2O2hzZPPmhgSAsXXwEIwJb841Ds7829lpcg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=intel.onmicrosoft.com; s=selector2-intel-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=RAZtUimKsbcV2e6YEMNqMX+tekhoicVvriaCHEg/VWk=; b=BXZbn+lso2/r/1LDVevO0WgqlAXj526n3ax8idGXWYlfyBISodBkGMt/j2I+VMO6ETdDsJerOpYoFP28ttU8vSuKACpHR0uRzwGtOw8dg6bzUvF3utmHvzyLN5DreEATLBKkO/Zj9Cs5Db6dw+FYyqpU+A4C1P4FF71IEswTT78= Received: from DM6PR11MB4073.namprd11.prod.outlook.com (2603:10b6:5:19f::22) by DM5PR1101MB2106.namprd11.prod.outlook.com (2603:10b6:4:54::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4308.21; Fri, 9 Jul 2021 01:08:22 +0000 Received: from DM6PR11MB4073.namprd11.prod.outlook.com ([fe80::b9b5:523d:7195:4f6c]) by DM6PR11MB4073.namprd11.prod.outlook.com ([fe80::b9b5:523d:7195:4f6c%3]) with mapi id 15.20.4287.034; Fri, 9 Jul 2021 01:08:22 +0000 From: "Bob Feng" To: "Kinney, Michael D" , "devel@edk2.groups.io" CC: Liming Gao , "Chen, Christine" Subject: Re: [Patch V2 1/3] BaseTools/Scripts: Fix GetMaintainer.py line endings Thread-Topic: [Patch V2 1/3] BaseTools/Scripts: Fix GetMaintainer.py line endings Thread-Index: AQHXdDKWfwBTmmIxDkmPnRkS6I37Sqs51VaA Date: Fri, 9 Jul 2021 01:08:21 +0000 Message-ID: References: <20210708195047.1649-1-michael.d.kinney@intel.com> <20210708195047.1649-2-michael.d.kinney@intel.com> In-Reply-To: <20210708195047.1649-2-michael.d.kinney@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: intel.com; dkim=none (message not signed) header.d=none;intel.com; dmarc=none action=none header.from=intel.com; x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 64050119-07a9-44e6-c176-08d942760bc9 x-ms-traffictypediagnostic: DM5PR1101MB2106: x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:125; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: mWmxAEQK0PiTAIGfFUKvKyMGabvP6p1pZ5/BOuMHFc6mVnlvytx8ipe2vgJctPaOoGEORAzeKselD1JKWlyrRvErO54RhGNd3/Sj0gRvW2XNFWjrXKD1ZkXLfpTz9yXgg/OUBw9e/v7OFxKJcjoS35uRsC+i4dqw5fQ/K/SPMbdEBmlaVrasODFc+HZw+SsfNjHkTsUQvf9ESTqrItMyoNpeGEehqazpGZSAMzwF0ShSUPeaHSBFxRMfF6vPcmuGKM4R1olzBiz4cT8SIVD+pTjwByAtjS0Y0cNlM28caFxtHIgmJ604MKylI30zKzoEKxLY1PLfwwvimAT/AQBNvfBWa3HljHTN7VvNxBTeEtBw2qpNPt8PMY2H5LiPI7Bm8cpVrHa05CqdHRe7n9/T78xQfQXhmoVfXiMa2iSRy4SGV+CxXbvMXh2fNxyzx/LLYV30WpDrbt6L0BsZVML2TXA0YnPgk0z9fh4XmSzJ97MTjzw45vGVd51xqf8KmKE3eBgxci+fArymj7BxGdEZSsKjsE9bw/LHdHyGYos4++eiJf6yHQ2X+E0xPXkk0GBi3Xmbiop9x0MZ1uXE0vBaX7oEthPpJbrOlAIEx8bzLLr09fsdT3YE0AqWWJAZvc0Rt+Mccw1bMKsG7/Ojk+ek2w== x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM6PR11MB4073.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(136003)(396003)(376002)(39860400002)(366004)(346002)(52536014)(6506007)(86362001)(107886003)(53546011)(26005)(2906002)(33656002)(30864003)(478600001)(4326008)(7696005)(83380400001)(71200400001)(76116006)(54906003)(66446008)(5660300002)(55016002)(66946007)(9686003)(110136005)(186003)(122000001)(38100700002)(66476007)(66556008)(64756008)(316002)(8936002)(8676002);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?MtsZc7N3jO2pRGW15wFs44jTsPuBiZJCQgVfPuyqSNuEyBvm62t+5KTDdKyX?= =?us-ascii?Q?Ls+kdG+UZ17Lykbu0Ah1MDcHqdEokHk1S2JwXSqzR0/yXfzJWCJ+2wxsXud8?= =?us-ascii?Q?iShYF4P+WcseRfwqbE0g3OhWi8kg14abMQJh6ZUBwPGNfhiEK+74ql4GQ3dc?= =?us-ascii?Q?3h4vDmGKQ4g3pBTYdSynQWoepZz1V5BaH59DJw3qMm7QUVfcXiUjdhzeG0sG?= =?us-ascii?Q?OTAmLK5Ow7KVjuqiQBIhYf0IICGs/n88mpLrgvfNZhJZueS6mOBwRzWHkGM2?= =?us-ascii?Q?7g48xYRej5nJ7yN23v4Evs4l+6zpNSB69skB6JpCzIX8D96YLZUVFhItMfT8?= =?us-ascii?Q?bPfKaUJFZ3uxTu/xGPKDsG0EZLpxELH8vR0JcxhAl65WbXHy7pWaHtPLlhLf?= =?us-ascii?Q?ftkBCQQqPrgUKEcfA2avzqQy0/i2ZASf6j5XuvHov7zn40JWk1PpVep6oszo?= =?us-ascii?Q?wyqDs1vfboAPTSW0QZbkuYnWzKT/ddpagdHRFqp4ACuxOLAGfmQd+FrsvHUW?= =?us-ascii?Q?OSWvxM2sFJLAxdvzuDxknzeCk+ppRgw+eAhj/mPWd9nxxp8kdN5sF0B9jfnr?= =?us-ascii?Q?AsesSXtkWCD73ArQqGmpjMP0gLArW/0WFtTEhkBXmS5iYUFXjhcP/0918lXZ?= =?us-ascii?Q?KQ5dYEtSIjc65cJhLOA55CaeBtHKNdzy3geidrIcTBu15CwbXchrpWcWHBM6?= =?us-ascii?Q?HPFQhzvjh/x2mruLrDKyY75o17fYdmIzckjg9itwpJDocAL0qsIisvErmRS+?= =?us-ascii?Q?e5aOWdfgE12xIDak3ZFktilk3j1yPCB5akZDbHOwYjdQrLMvZPkimweJPibV?= =?us-ascii?Q?4QAWGWShv4JbO9dqR9dJd1yjT17t9bul90fDz2Bb9xDLQOTjJyJ+IJLAXVYd?= =?us-ascii?Q?rdhjwktOUAwLyHqu/GHbjDA7nweV10YJia1QB+USjG1R0ZVRy8bR+v3HYMtu?= =?us-ascii?Q?uFEZQQuisCKJT53qNDceAMjs6MIo2tUG2T0CB8FnAJUVIlitmcFlVFmm4TrT?= =?us-ascii?Q?w2L/k7hr2U45KHKTeYPrZT35SAHd/gCtB6JwmJ2ryhjtEtEszu/r3RdnUhhr?= =?us-ascii?Q?zRu2dNU2WL0VC0Y/9vDgxOrmhJ57AIHM4WGHfoML2F6bgInORAMVriO9uDW7?= =?us-ascii?Q?sETiPdMrlik/B34u1tch6P2/ngDpiG8P306oJUtsZ0Onye58FM0CnsmixY5u?= =?us-ascii?Q?lydx386jIFIrFRkl3xWPgzv8HbA/E+hsSRlfaG1Z5/BkEv2Dq1CWqmsGfItk?= =?us-ascii?Q?NPRoZ88D1NRUgMYkEokNrOcAoqbZJZpDMBvLFFYEK15T+vIUZL+sb4+IwnFZ?= =?us-ascii?Q?Poc=3D?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: DM6PR11MB4073.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 64050119-07a9-44e6-c176-08d942760bc9 X-MS-Exchange-CrossTenant-originalarrivaltime: 09 Jul 2021 01:08:21.9882 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: MDgYojy7pIwZpEG2moJY8F5Ls0Y2rRVFkvAkLes/aByMaP+1hKapx0fvu+Di/i7FDPx0F90Mdwq4t4kT/ypong== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR1101MB2106 Return-Path: bob.c.feng@intel.com X-OriginatorOrg: intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Bob Feng -----Original Message----- From: Kinney, Michael D =20 Sent: Friday, July 9, 2021 3:51 AM To: devel@edk2.groups.io Cc: Feng, Bob C ; Liming Gao ; Chen, Christine Subject: [Patch V2 1/3] BaseTools/Scripts: Fix GetMaintainer.py line ending= s Cc: Bob Feng Cc: Liming Gao Cc: Yuwei Chen Signed-off-by: Michael D Kinney --- BaseTools/Scripts/GetMaintainer.py | 380 ++++++++++++++--------------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/BaseTools/Scripts/GetMaintainer.py b/BaseTools/Scripts/GetMain= tainer.py index ed7bc7dc2b88..5ec851554d64 100644 --- a/BaseTools/Scripts/GetMaintainer.py +++ b/BaseTools/Scripts/GetMaintainer.py @@ -1,194 +1,194 @@ -## @file -# Retrieves the people to request review from on submission of a commit. -# -# Copyright (c) 2019, Linaro Ltd. All rights reserved.
-# -# SPDX-Li= cense-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 =3D { - 'exclude': re.compile(r'^X:\s*(?P.*?)\r*$'), - 'file': re.compile(r'^F:\s*(?P.*?)\r*$'), - 'list': re.compile(r'^L:\s*(?P.*?)\r*$'), - 'maintainer': re.compile(r'^M:\s*(?P.*<.*?>)\r*$'), - 'reviewer': re.compile(r'^R:\s*(?P.*?)\r*$'), - 'status': re.compile(r'^S:\s*(?P.*?)\r*$'), - 'tree': re.compile(r'^T:\s*(?P.*?)\r*$'), - 'webpage': re.compile(r'^W:\s*(?P.*?)\r*$') -} - -def printsection(section): - """Prints out the dictionary describing a Maintainers.txt section.""" - print('=3D=3D=3D') - 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 =3D pattern.replace('.', r'\.') - pattern =3D pattern.replace('?', r'.') - pattern =3D pattern.replace('*', r'.*') - - if pattern.endswith('/'): - pattern +=3D r'.*' - elif pattern.endswith('.*'): - pattern =3D pattern[:-2] - pattern +=3D 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 =3D pattern_to_regex(pattern) - - match =3D re.match(regex, path) - if match: - # Check if there is an exclude pattern that applies - for pattern in section['exclude']: - regex =3D pattern_to_regex(pattern) - - match =3D 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 =3D [] - lists =3D [] +## @file +# Retrieves the people to request review from on submission of a commit. +# +# Copyright (c) 2019, Linaro Ltd. All rights reserved.
# # =20 +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 =3D { + 'exclude': re.compile(r'^X:\s*(?P.*?)\r*$'), + 'file': re.compile(r'^F:\s*(?P.*?)\r*$'), + 'list': re.compile(r'^L:\s*(?P.*?)\r*$'), + 'maintainer': re.compile(r'^M:\s*(?P.*<.*?>)\r*$'), + 'reviewer': re.compile(r'^R:\s*(?P.*?)\r*$'), + 'status': re.compile(r'^S:\s*(?P.*?)\r*$'), + 'tree': re.compile(r'^T:\s*(?P.*?)\r*$'), + 'webpage': re.compile(r'^W:\s*(?P.*?)\r*$') +} + +def printsection(section): + """Prints out the dictionary describing a Maintainers.txt section.""" + print('=3D=3D=3D') + 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 =3D pattern.replace('.', r'\.') + pattern =3D pattern.replace('?', r'.') + pattern =3D pattern.replace('*', r'.*') + + if pattern.endswith('/'): + pattern +=3D r'.*' + elif pattern.endswith('.*'): + pattern =3D pattern[:-2] + pattern +=3D 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 =3D pattern_to_regex(pattern) + + match =3D re.match(regex, path) + if match: + # Check if there is an exclude pattern that applies + for pattern in section['exclude']: + regex =3D pattern_to_regex(pattern) + + match =3D 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 =3D [] + lists =3D [] nowarn_status =3D ['Supported', 'Maintained'] - - if path_in_section(path, section): + + if path_in_section(path, section): for status in section['status']: if status not in nowarn_status: print('WARNING: Maintained status for "%s" is \'%s\'!' % (= path, status)) - for address in section['maintainer'], section['reviewer']: - # Convert to list if necessary - if isinstance(address, list): - maintainers +=3D address - else: - lists +=3D [address] - for address in section['list']: - # Convert to list if necessary - if isinstance(address, list): - lists +=3D address - else: - lists +=3D [address] - - return maintainers, lists - -def get_maintainers(path, sections, level=3D0): - """For 'path', iterates over all sections, returning maintainers - for matching ones.""" - maintainers =3D [] - lists =3D [] - for section in sections: - tmp_maint, tmp_lists =3D get_section_maintainers(path, section) - if tmp_maint: - maintainers +=3D tmp_maint - if tmp_lists: - lists +=3D tmp_lists - - if not maintainers: - # If no match found, look for match for (nonexistent) file - # REPO.working_dir/ - print('"%s": no maintainers found, looking for default' % path) - if level =3D=3D 0: - maintainers =3D get_maintainers('', sections, level= =3Dlevel + 1) - else: - print("No 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 it= s key.""" - for key, expression in EXPRESSIONS.items(): - match =3D 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 =3D text.readline() - sectionlist =3D [] - section =3D defaultdict(list) - while line: - key, value =3D parse_maintainers_line(line) - if key and value: - section[key].append(value) - - line =3D 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 'ar= gs'.""" - commit =3D repo.commit(args.commit) - return commit.stats.files - -if __name__ =3D=3D '__main__': - PARSER =3D argparse.ArgumentParser( - description=3D'Retrieves information on who to cc for review on a = given commit') - PARSER.add_argument('commit', - action=3D"store", - help=3D'git revision to examine (default: HEAD)', - nargs=3D'?', - default=3D'HEAD') - PARSER.add_argument('-l', '--lookup', - help=3D'Find section matches for path LOOKUP', - required=3DFalse) - ARGS =3D PARSER.parse_args() - - REPO =3D SetupGit.locate_repo() - - CONFIG_FILE =3D os.path.join(REPO.working_dir, 'Maintainers.txt') - - SECTIONS =3D parse_maintainers_file(CONFIG_FILE) - - if ARGS.lookup: - FILES =3D [ARGS.lookup] - else: - FILES =3D get_modified_files(REPO, ARGS) - - ADDRESSES =3D [] - - for file in FILES: - print(file) - addresslist =3D get_maintainers(file, SECTIONS) - if addresslist: - ADDRESSES +=3D addresslist - - for address in list(OrderedDict.fromkeys(ADDRESSES)): - print(' %s' % address) + for address in section['maintainer'], section['reviewer']: + # Convert to list if necessary + if isinstance(address, list): + maintainers +=3D address + else: + lists +=3D [address] + for address in section['list']: + # Convert to list if necessary + if isinstance(address, list): + lists +=3D address + else: + lists +=3D [address] + + return maintainers, lists + +def get_maintainers(path, sections, level=3D0): + """For 'path', iterates over all sections, returning maintainers + for matching ones.""" + maintainers =3D [] + lists =3D [] + for section in sections: + tmp_maint, tmp_lists =3D get_section_maintainers(path, section) + if tmp_maint: + maintainers +=3D tmp_maint + if tmp_lists: + lists +=3D tmp_lists + + if not maintainers: + # If no match found, look for match for (nonexistent) file + # REPO.working_dir/ + print('"%s": no maintainers found, looking for default' % path) + if level =3D=3D 0: + maintainers =3D get_maintainers('', sections, level= =3Dlevel + 1) + else: + print("No 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 it= s key.""" + for key, expression in EXPRESSIONS.items(): + match =3D 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 =3D text.readline() + sectionlist =3D [] + section =3D defaultdict(list) + while line: + key, value =3D parse_maintainers_line(line) + if key and value: + section[key].append(value) + + line =3D 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 'ar= gs'.""" + commit =3D repo.commit(args.commit) + return commit.stats.files + +if __name__ =3D=3D '__main__': + PARSER =3D argparse.ArgumentParser( + description=3D'Retrieves information on who to cc for review on a = given commit') + PARSER.add_argument('commit', + action=3D"store", + help=3D'git revision to examine (default: HEAD)', + nargs=3D'?', + default=3D'HEAD') + PARSER.add_argument('-l', '--lookup', + help=3D'Find section matches for path LOOKUP', + required=3DFalse) + ARGS =3D PARSER.parse_args() + + REPO =3D SetupGit.locate_repo() + + CONFIG_FILE =3D os.path.join(REPO.working_dir, 'Maintainers.txt') + + SECTIONS =3D parse_maintainers_file(CONFIG_FILE) + + if ARGS.lookup: + FILES =3D [ARGS.lookup] + else: + FILES =3D get_modified_files(REPO, ARGS) + + ADDRESSES =3D [] + + for file in FILES: + print(file) + addresslist =3D get_maintainers(file, SECTIONS) + if addresslist: + ADDRESSES +=3D addresslist + + for address in list(OrderedDict.fromkeys(ADDRESSES)): + print(' %s' % address) -- 2.32.0.windows.1