Skip to content

Commit 7bc8fdd

Browse files
committed
scripts: west_commands: patch: Fix modules patching mechanism
The script has been using the `zephyr_module.parse_modules` method that is returning only these west project (repositories listed in west manifest) that have module YML/YAML files. Other west project were dropped from the list wast was resulting in patches being skipped for Zephyr and west projects the don't have module file. This patch changes the used method to the one that list all west projects that are specified in the west manifest. Variables and arguments have been changed from `modules` to `projects` to be aligned with West's difinitions. Fixes: zephyrproject-rtos#96925 Signed-off-by: Adam Wojasinski <[email protected]>
1 parent c77e5a6 commit 7bc8fdd

File tree

2 files changed

+70
-68
lines changed

2 files changed

+70
-68
lines changed

doc/develop/west/zephyr-cmds.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ Additional tips:
314314
Working with patches: ``west patch``
315315
************************************
316316

317-
The ``patch`` command allows users to apply patches to Zephyr or Zephyr modules
317+
The ``patch`` command allows users to apply patches to Zephyr and other west projects
318318
in a controlled manner that makes automation and tracking easier for external applications that
319319
use the :ref:`T2 star topology <west-t2>`. The :ref:`patches.yml <patches-yml>` file stores
320320
metadata about patch files and fills-in the gaps between official Zephyr releases, so that users
@@ -347,8 +347,8 @@ workspace:
347347
348348
In this example, the :ref:`west manifest <west-manifests>` file, ``west.yml``, would pin to a
349349
specific Zephyr revision (e.g. ``v4.1.0``) and apply patches against that revision of Zephyr and
350-
the specific revisions of other modules used in the application. However, this application needs
351-
two changes in order to meet requirements; one for Zephyr and another for MCUBoot.
350+
the specific revisions of other west projects used in the application. However, this application
351+
needs two changes in order to meet requirements; one for Zephyr and another for MCUBoot.
352352

353353
.. _patches-yml:
354354

scripts/west_commands/patch.py

Lines changed: 67 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def do_add_parser(self, parser_adder):
104104
"-b",
105105
"--patch-base",
106106
help=f"""
107-
Directory containing patch files (absolute or relative to module dir,
107+
Directory containing patch files (absolute or relative to project dir,
108108
default: {WEST_PATCH_BASE})""",
109109
metavar="DIR",
110110
type=Path,
@@ -113,7 +113,7 @@ def do_add_parser(self, parser_adder):
113113
"-l",
114114
"--patch-yml",
115115
help=f"""
116-
Path to patches.yml file (absolute or relative to module dir,
116+
Path to patches.yml file (absolute or relative to project dir,
117117
default: {WEST_PATCH_YAML})""",
118118
metavar="FILE",
119119
type=Path,
@@ -127,26 +127,26 @@ def do_add_parser(self, parser_adder):
127127
)
128128
parser.add_argument(
129129
"-sm",
130-
"--src-module",
131-
dest="src_module",
132-
metavar="MODULE",
130+
"--src-project",
131+
dest="src_project",
132+
metavar="PROJECT",
133133
type=str,
134134
help="""
135-
Zephyr module containing the patch definition (name, absolute path or
135+
Zephyr project containing the patch definition (name, absolute path or
136136
path relative to west-workspace)""",
137137
)
138138
parser.add_argument(
139139
"-dm",
140-
"--dst-module",
140+
"--dst-project",
141141
action="append",
142-
dest="dst_modules",
143-
metavar="MODULE",
142+
dest="dst_project",
143+
metavar="PROJECT",
144144
type=str,
145145
help="""
146-
Zephyr module to run the 'patch' command for.
146+
Zephyr project to run the 'patch' command for.
147147
Option can be passed multiple times.
148148
If this option is not given, the 'patch' command will run for Zephyr
149-
and all modules.""",
149+
and all projects.""",
150150
)
151151

152152
subparsers = parser.add_subparsers(
@@ -227,13 +227,13 @@ def do_add_parser(self, parser_adder):
227227
help="Github Pull Request ID",
228228
)
229229
gh_fetch_arg_parser.add_argument(
230-
"-m",
231-
"--module",
230+
"-p",
231+
"--project",
232232
metavar="DIR",
233233
action="store",
234234
required=True,
235235
type=Path,
236-
help="Module path",
236+
help="Project path",
237237
)
238238
gh_fetch_arg_parser.add_argument(
239239
"-s",
@@ -272,15 +272,15 @@ def filter_args(self, args):
272272

273273
topdir = Path(self.topdir)
274274

275-
if args.src_module is not None:
276-
mod_path = self.get_module_path(args.src_module)
277-
if mod_path is None:
278-
self.die(f'Source module "{args.src_module}" not found')
275+
if args.src_project is not None:
276+
prj_path = self.get_project_path(args.src_project)
277+
if prj_path is None:
278+
self.die(f'Source project "{args.src_project}" not found')
279279
if args.patch_base is not None and args.patch_base.is_absolute():
280-
self.die("patch-base must not be an absolute path in combination with src-module")
280+
self.die("patch-base must not be an absolute path in combination with src-project")
281281
if args.patch_yml is not None and args.patch_yml.is_absolute():
282-
self.die("patch-yml must not be an absolute path in combination with src-module")
283-
manifest_dir = topdir / mod_path
282+
self.die("patch-yml must not be an absolute path in combination with src-project")
283+
manifest_dir = topdir / prj_path
284284
else:
285285
manifest_dir = topdir / manifest_path
286286

@@ -299,8 +299,8 @@ def filter_args(self, args):
299299
elif not args.west_workspace.is_absolute():
300300
args.west_workspace = topdir / args.west_workspace
301301

302-
if args.dst_modules is not None:
303-
args.dst_modules = [self.get_module_path(m) for m in args.dst_modules]
302+
if args.dst_project is not None:
303+
args.dst_project = [self.get_project_path(m) for m in args.dst_project]
304304

305305
def load_yml(self, args, allow_missing):
306306
if not os.path.isfile(args.patch_yml):
@@ -339,23 +339,24 @@ def do_run(self, args, _):
339339
"gh-fetch": self.gh_fetch,
340340
}
341341

342-
method[args.subcommand](args, yml, args.dst_modules)
342+
method[args.subcommand](args, yml, args.dst_project)
343343

344-
def apply(self, args, yml, dst_mods=None):
344+
def apply(self, args, yml, dst_prjs=None):
345345
patches = yml.get("patches", [])
346+
346347
if not patches:
347348
return
348349

349350
patch_count = 0
350351
failed_patch = None
351-
patched_mods = set()
352+
patched_prjs = set()
352353

353354
for patch_info in patches:
354-
mod = self.get_module_path(patch_info["module"])
355-
if mod is None:
355+
prj = self.get_project_path(patch_info["module"])
356+
if prj is None:
356357
continue
357358

358-
if dst_mods and mod not in dst_mods:
359+
if dst_prjs and prj not in dst_prjs:
359360
continue
360361

361362
pth = patch_info["path"]
@@ -385,13 +386,13 @@ def apply(self, args, yml, dst_mods=None):
385386
self.dbg("OK")
386387
patch_count += 1
387388

388-
mod_path = Path(args.west_workspace) / mod
389-
patched_mods.add(mod)
389+
prj_path = Path(args.west_workspace) / prj
390+
patched_prjs.add(prj)
390391

391-
self.dbg(f"patching {mod}... ", end="")
392+
self.dbg(f"patching {prj}... ", end="")
392393
apply_cmd += patch_path
393394
apply_cmd_list.extend([patch_path])
394-
proc = subprocess.run(apply_cmd_list, cwd=mod_path)
395+
proc = subprocess.run(apply_cmd_list, cwd=prj_path)
395396
if proc.returncode:
396397
self.dbg("FAIL")
397398
self.err(proc.stderr)
@@ -404,11 +405,11 @@ def apply(self, args, yml, dst_mods=None):
404405
return
405406

406407
if args.roll_back:
407-
self.clean(args, yml, patched_mods)
408+
self.clean(args, yml, patched_prjs)
408409

409410
self.die(f"failed to apply patch {failed_patch}")
410411

411-
def clean(self, args, yml, dst_mods=None):
412+
def clean(self, args, yml, dst_prjs=None):
412413
clean_cmd = yml["clean-command"]
413414
checkout_cmd = yml["checkout-command"]
414415

@@ -419,52 +420,52 @@ def clean(self, args, yml, dst_mods=None):
419420
clean_cmd_list = shlex.split(clean_cmd)
420421
checkout_cmd_list = shlex.split(checkout_cmd)
421422

422-
for mod in yml.get("patches", []):
423-
m = self.get_module_path(mod.get("module"))
423+
for prj in yml.get("patches", []):
424+
m = self.get_project_path(prj.get("module"))
424425
if m is None:
425426
continue
426-
if dst_mods and m not in dst_mods:
427+
if dst_prjs and m not in dst_prjs:
427428
continue
428-
mod_path = Path(args.west_workspace) / m
429+
prj_path = Path(args.west_workspace) / m
429430

430431
try:
431432
if checkout_cmd:
432-
self.dbg(f"Running '{checkout_cmd}' in {mod}.. ", end="")
433-
proc = subprocess.run(checkout_cmd_list, capture_output=True, cwd=mod_path)
433+
self.dbg(f"Running '{checkout_cmd}' in {prj}.. ", end="")
434+
proc = subprocess.run(checkout_cmd_list, capture_output=True, cwd=prj_path)
434435
if proc.returncode:
435436
self.dbg("FAIL")
436-
self.err(f"{checkout_cmd} failed for {mod}\n{proc.stderr}")
437+
self.err(f"{checkout_cmd} failed for {prj}\n{proc.stderr}")
437438
else:
438439
self.dbg("OK")
439440

440441
if clean_cmd:
441-
self.dbg(f"Running '{clean_cmd}' in {mod}.. ", end="")
442-
proc = subprocess.run(clean_cmd_list, capture_output=True, cwd=mod_path)
442+
self.dbg(f"Running '{clean_cmd}' in {prj}.. ", end="")
443+
proc = subprocess.run(clean_cmd_list, capture_output=True, cwd=prj_path)
443444
if proc.returncode:
444445
self.dbg("FAIL")
445-
self.err(f"{clean_cmd} failed for {mod}\n{proc.stderr}")
446+
self.err(f"{clean_cmd} failed for {prj}\n{proc.stderr}")
446447
else:
447448
self.dbg("OK")
448449

449450
except Exception as e:
450451
# If this fails for some reason, just log it and continue
451-
self.err(f"failed to clean up {mod}: {e}")
452+
self.err(f"failed to clean up {prj}: {e}")
452453

453-
def list(self, args, yml, dst_mods=None):
454+
def list(self, args, yml, dst_prjs=None):
454455
patches = yml.get("patches", [])
455456
if not patches:
456457
return
457458

458459
for patch_info in patches:
459-
if dst_mods and self.get_module_path(patch_info["module"]) not in dst_mods:
460+
if dst_prjs and self.get_project_path(patch_info["project"]) not in dst_prjs:
460461
continue
461462
self.inf(patch_info)
462463

463-
def gh_fetch(self, args, yml, mods=None):
464-
if mods:
464+
def gh_fetch(self, args, yml, prjs=None):
465+
if prjs:
465466
self.die(
466-
"Module filters are not available for the gh-fetch subcommand, "
467-
"pass a single -m/--module argument after the subcommand."
467+
"project filters are not available for the gh-fetch subcommand, "
468+
"pass a single -m/--project argument after the subcommand."
468469
)
469470

470471
try:
@@ -487,7 +488,7 @@ def gh_fetch(self, args, yml, mods=None):
487488
patch_info = {
488489
"path": filename,
489490
"sha256sum": self.get_file_sha256sum(args.patch_base / filename),
490-
"module": str(args.module),
491+
"module": str(args.project),
491492
"author": cm.commit.author.name or "Hidden",
492493
"email": cm.commit.author.email or "[email protected]",
493494
"date": cm.commit.author.date.strftime("%Y-%m-%d"),
@@ -504,7 +505,7 @@ def gh_fetch(self, args, yml, mods=None):
504505
patch_info = {
505506
"path": filename,
506507
"sha256sum": self.get_file_sha256sum(args.patch_base / filename),
507-
"module": str(args.module),
508+
"module": str(args.project),
508509
"author": pr.user.name or "Hidden",
509510
"email": pr.user.email or "[email protected]",
510511
"date": pr.created_at.strftime("%Y-%m-%d"),
@@ -532,23 +533,24 @@ def get_file_sha256sum(filename: Path) -> str:
532533

533534
return digest.hexdigest()
534535

535-
def get_module_path(self, module_name_or_path):
536-
if module_name_or_path is None:
536+
def get_project_path(self, project_name_or_path):
537+
if project_name_or_path is None:
537538
return None
538539

539540
topdir = Path(self.topdir)
540541

541-
if Path(module_name_or_path).is_absolute():
542-
if Path(module_name_or_path).is_dir():
543-
return Path(module_name_or_path).resolve().relative_to(topdir)
542+
if Path(project_name_or_path).is_absolute():
543+
if Path(project_name_or_path).is_dir():
544+
return Path(project_name_or_path).resolve().relative_to(topdir)
544545
return None
545546

546-
if (topdir / module_name_or_path).is_dir():
547-
return Path(module_name_or_path)
547+
if (topdir / project_name_or_path).is_dir():
548+
return Path(project_name_or_path)
549+
550+
all_projects = zephyr_module.west_projects(self.manifest)['projects']
548551

549-
all_modules = zephyr_module.parse_modules(ZEPHYR_BASE, self.manifest)
550-
for m in all_modules:
551-
if m.meta['name'] == module_name_or_path:
552-
return Path(m.project).relative_to(topdir)
552+
for p in all_projects:
553+
if p.name == project_name_or_path:
554+
return Path(p.abspath).relative_to(topdir)
553555

554556
return None

0 commit comments

Comments
 (0)