summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorQuentin Schulz <quentin.schulz@cherry.de>2025-02-05 17:16:01 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-02-06 10:40:10 +0000
commit0698d606be1a03e7dbdb8b97ac59a6f018215b17 (patch)
treeef08f4f2137fa780ec80b6b987970f6e0f6bfd8d /scripts
parent64ef07f6c4ad1e9d836236f71032b77f7c6b5248 (diff)
downloadpoky-0698d606be1a03e7dbdb8b97ac59a6f018215b17.tar.gz
scripts: add b4-wrapper for poky
poky is a combo-layer containing BitBake, OpenEmbedded-Core and Yocto Documentation source code into one big repo. It is not uncommon to have people develop patches for either of those projects from a poky git repo. However, it is unlikely those patches are to be sent to the poky mailing list as very few files contained in the poky git repo actually are poky-specific. So we need a way to identify to which mailing list a patch is destined to be sent. Additionally, because the source code in openembedded-core is merged/imported at the root of the git repo of poky, its .b4-config introduced in the previous commit will be used if not overridden (which will be done in a separate commit specific to the poky git repo). We need to provide a different .b4-config in poky. Therefore, this wrapper is used to identify automatically which mailing list a patch series needs to be sent to (via b4 prep --auto-to-cc) and does some additional checks (via b4 prep --check) such as making sure a patch doesn't modify two different projects at the same time or that multiple projects are modified by different patches in the same patch series. This wrapper script is meant to be used by poky's .b4-config. Ideally the b4 prep --check part could be offloaded to `patchtest` once it supports running on source different from OE-Core. Note that b4 makes sure that an address doesn't appear twice in the recipient list. There's also no priority in the type of recipient list, so if the address appears first in Cc and then in To, only the Cc will be added. The opposite is true as well. (From OE-Core rev: a1d629a0823cf724bda607ef8d88ee4f722c3a08) Signed-off-by: Quentin Schulz <quentin.schulz@cherry.de> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/b4-wrapper-poky.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/scripts/b4-wrapper-poky.py b/scripts/b4-wrapper-poky.py
new file mode 100755
index 0000000000..30a7b95ff3
--- /dev/null
+++ b/scripts/b4-wrapper-poky.py
@@ -0,0 +1,178 @@
1#!/usr/bin/env python3
2#
3# Copyright OpenEmbedded Contributors
4#
5# SPDX-License-Identifier: MIT
6#
7# This script is to be called by b4:
8# - through the b4.prep-perpatch-check-cmd with "prep-perpatch-check-cmd" as
9# first argument,
10# - through b4.send-auto-cc-cmd with "send-auto-cc-cmd" as first argument,
11# - through b4.send-auto-to-cmd with "send-auto-to-cmd" as first argument,
12#
13# When prep-perpatch-check-cmd is passsed:
14#
15# This checks that a patch makes changes to at most one project in the poky
16# combo repo (that is, out of yocto-docs, bitbake, openembedded-core combined
17# into poky and the poky-specific files).
18#
19# Printing something to stdout in this file will result in b4 prep --check fail
20# for the currently parsed patch.
21#
22# It checks that all patches in the series make changes to at most one project.
23#
24# When send-auto-cc-cmd is passed:
25#
26# This returns the list of Cc recipients for a patch.
27#
28# When send-auto-to-cmd is passed:
29#
30# This returns the list of To recipients for a patch.
31#
32# This script takes as stdin a patch.
33
34import pathlib
35import re
36import shutil
37import subprocess
38import sys
39
40cmd = sys.argv[1]
41
42patch = sys.stdin.readlines()
43
44# Subject field is used to identify the last patch as this script is called for
45# each patch. We edit the same file in a series by using the References field
46# unique identifier to check which projects are modified by earlier patches in
47# the series. To avoid cluttering the disk, the last patch in the list removes
48# that shared file.
49re_subject = re.compile(r'^Subject:.*\[.*PATCH.*\s(\d+)/\1')
50re_ref = re.compile(r'^References: <(.*)>$')
51
52subject = None
53ref = None
54
55if not shutil.which("lsdiff"):
56 print("lsdiff missing from host, please install patchutils")
57 sys.exit(-1)
58
59try:
60 one_patch_series = False
61 for line in patch:
62 subject = re_subject.match(line)
63 if subject:
64 # Handle [PATCH 1/1]
65 if subject.group(1) == 1:
66 one_patch_series = True
67 break
68 if re.match(r'^Subject: .*\[.*PATCH[^/]*\]', line):
69 # Single patch is named [PATCH] but if there are prefix, it could be
70 # [PATCH prefix], so handle everything that doesn't have a /
71 # character which is used as separator between current patch number
72 # and total patch number
73 one_patch_series = True
74 break
75
76 if cmd == "prep-perpatch-check-cmd" and not one_patch_series:
77 for line in patch:
78 ref = re_ref.match(line)
79 if ref:
80 break
81
82 if not ref:
83 print("Failed to find ref to cover letter (References:)...")
84 sys.exit(-2)
85
86 ref = ref.group(1)
87 series_check = pathlib.Path(f".tmp-{ref}")
88
89 patch = "".join(patch)
90
91 if cmd == "send-auto-cc-cmd":
92 # Patches to BitBake documentation should also go to yocto-docs mailing list
93 project_paths = {
94 "yocto-docs": ["bitbake/doc/*"],
95 }
96 else:
97 project_paths = {
98 "bitbake": ["bitbake/*"],
99 "yocto-docs": ["documentation/*"],
100 "poky": [
101 "meta-poky/*",
102 "meta-yocto-bsp/*",
103 "README.hardware.md",
104 "README.poky.md",
105 ],
106 }
107
108 # List of projects touched by this patch
109 projs = []
110
111 # Any file not matched by any path in project_paths means it is from
112 # OE-Core.
113 # When matching some path in project_paths, remove the matched files from
114 # that list.
115 files_left = subprocess.check_output(["lsdiff", "--strip-match=1", "--strip=1"],
116 input=patch, text=True)
117 files_left = set(files_left)
118
119 for proj, proj_paths in project_paths.items():
120 lsdiff_args = [f"--include={path}" for path in proj_paths]
121 files = subprocess.check_output(["lsdiff", "--strip-match=1", "--strip=1"] + lsdiff_args,
122 input=patch, text=True)
123 if len(files):
124 files_left = files_left - set(files)
125 projs.append(proj)
126 continue
127
128 # Handle patches made with --no-prefix
129 files = subprocess.check_output(["lsdiff"] + lsdiff_args,
130 input=patch, text=True)
131 if len(files):
132 files_left = files_left - set(files)
133 projs.append(proj)
134
135 # Catch-all for everything not poky-specific or in bitbake/yocto-docs
136 if len(files_left) and cmd != "send-auto-cc-cmd":
137 projs.append("openembedded-core")
138
139 if cmd == "prep-perpatch-check-cmd":
140 if len(projs) > 1:
141 print(f"Diff spans more than one project ({', '.join(sorted(projs))}), split into multiple commits...")
142 sys.exit(-3)
143
144 # No need to check other patches in the series as there aren't any
145 if one_patch_series:
146 sys.exit(0)
147
148 # This should be replaced once b4 supports prep-perseries-check-cmd (or something similar)
149
150 if series_check.exists():
151 # NOT race-free if b4 decides to parallelize prep-perpatch-check-cmd
152 series_projs = series_check.read_text().split('\n')
153 else:
154 series_projs = []
155
156 series_projs += projs
157 uniq_series_projs = set(series_projs)
158 # NOT race-free, if b4 decides to parallelize prep-perpatch-check-cmd
159 series_check.write_text('\n'.join(uniq_series_projs))
160
161 if len(uniq_series_projs) > 1:
162 print(f"Series spans more than one project ({', '.join(sorted(uniq_series_projs))}), split into multiple series...")
163 sys.exit(-4)
164 else: # send-auto-cc-cmd / send-auto-to-cmd
165 ml_projs = {
166 "bitbake": "bitbake-devel@lists.openembedded.org",
167 "yocto-docs": "docs@lists.yoctoproject.org",
168 "poky": "poky@lists.yoctoproject.org",
169 "openembedded-core": "openembedded-core@lists.openembedded.org",
170 }
171
172 print("\n".join([ml_projs[ml] for ml in projs]))
173
174 sys.exit(0)
175finally:
176 # Last patch in the series, cleanup tmp file
177 if subject and ref and series_check.exists():
178 series_check.unlink()