[PATCH 2/2] pw_maintainers_cli: download series mbox for maintainers lookup
David Marchand
david.marchand at redhat.com
Fri Jul 24 18:21:42 CEST 2026
When looking up trees or maintainers for a series, the script was
fetching each patch individually just to extract filenames from diffs.
For a series with N patches, this resulted in N+1 API requests to
patchwork.
Download the series mbox once and parse filenames locally for the
list-trees and list-maintainers commands, reducing patchwork load
from N+1 requests to 2.
The set-pw-delegate command still needs to fetch individual patches
to check the delegate status, so it keeps the original behavior.
Before:
DEBUG:urllib3.connectionpool:https://patchwork.dpdk.org:443 "GET /api/1.2/series/38789/ HTTP/1.1" 200 3056
DEBUG:urllib3.connectionpool:https://patchwork.dpdk.org:443 "GET /api/1.2/patches/166911/ HTTP/1.1" 200 28237
DEBUG:urllib3.connectionpool:https://patchwork.dpdk.org:443 "GET /api/1.2/patches/166912/ HTTP/1.1" 200 21289
DEBUG:urllib3.connectionpool:https://patchwork.dpdk.org:443 "GET /api/1.2/patches/166913/ HTTP/1.1" 200 161492
After:
DEBUG:urllib3.connectionpool:https://patchwork.dpdk.org:443 "GET /api/1.2/series/38789/ HTTP/1.1" 200 3056
DEBUG:urllib3.connectionpool:https://patchwork.dpdk.org:443 "GET /series/38789/mbox/ HTTP/1.1" 200 191863
Signed-off-by: David Marchand <david.marchand at redhat.com>
---
tools/pw_maintainers_cli.py | 59 ++++++++++++++++++++++++++++++++-----
1 file changed, 52 insertions(+), 7 deletions(-)
diff --git a/tools/pw_maintainers_cli.py b/tools/pw_maintainers_cli.py
index 15ec0a7..abcf3c3 100755
--- a/tools/pw_maintainers_cli.py
+++ b/tools/pw_maintainers_cli.py
@@ -46,6 +46,7 @@ import sys
import re
import argparse
import fnmatch
+import tempfile
from requests.exceptions import HTTPError
@@ -58,6 +59,43 @@ from git_pw import patch as git_pw_patch
LOG = logging.getLogger(__name__)
+def download_series_mbox(mbox_url):
+ """Download series mbox and return its content."""
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.mbox', delete=False) as f:
+ mbox_path = f.name
+
+ LOG.debug('GET %s', mbox_url)
+ api.download(mbox_url, None, mbox_path)
+
+ with open(mbox_path, 'r') as f:
+ content = f.read()
+ os.unlink(mbox_path)
+ return content
+
+
+def find_filenames_in_mbox(mbox_content):
+ """Extract changed filenames from an mbox file.
+
+ Parses the mbox content to find all diff headers and extracts
+ the filenames being modified.
+ """
+ filenames = {}
+ filename_re = re.compile(r'^(---|\+\+\+) (\S+)')
+
+ for line in mbox_content.split('\n'):
+ filename_match = filename_re.match(line)
+ if not filename_match:
+ continue
+ filename = filename_match.group(2)
+ if filename.startswith('/dev/null'):
+ continue
+ # Strip the a/ or b/ prefix
+ filename = '/'.join(filename.split('/')[1:])
+ if filename:
+ filenames[filename] = True
+
+ return sorted(filenames.keys())
+
MAINTAINERS_FILE_PATH = os.environ.get('MAINTAINERS_FILE_PATH')
if not MAINTAINERS_FILE_PATH:
print('MAINTAINERS_FILE_PATH is not set.', file=sys.stderr)
@@ -383,17 +421,24 @@ if __name__ == '__main__':
maintainers = Maintainers()
patch_list = []
+ files = []
if resource_type == 'patch':
patch_list.append(_git_pw.api_get('patches', _id))
+ for patch in patch_list:
+ files += Diff.find_filenames(patch['diff'])
else:
series = _git_pw.api_get('series', _id)
- patch_list = [
- _git_pw.api_get('patches', patch['id'])
- for patch in series['patches']]
-
- files = []
- for patch in patch_list:
- files += Diff.find_filenames(patch['diff'])
+ if command == 'set-pw-delegate':
+ # Need full patch data for delegate status
+ patch_list = [
+ _git_pw.api_get('patches', patch['id'])
+ for patch in series['patches']]
+ for patch in patch_list:
+ files += Diff.find_filenames(patch['diff'])
+ else:
+ # Download mbox once to extract filenames (2 requests instead of N+1)
+ mbox_content = download_series_mbox(series['mbox'])
+ files = find_filenames_in_mbox(mbox_content)
tree = maintainers.get_tree(files)
--
2.54.0
More information about the ci
mailing list