Skip to content

Commit 4455cd7

Browse files
mt-gjoergeskartben
authored andcommitted
scripts: west_commands: patch: add src module argument
The src-module argument can be used to select the module in which west patch searches for patch definitions. This commit also allows the use of module names instead of the path. Signed-off-by: Gerhard Jörges <[email protected]>
1 parent 978f559 commit 4455cd7

File tree

2 files changed

+96
-45
lines changed

2 files changed

+96
-45
lines changed

scripts/schemas/patch-schema.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ schema;patch-schema:
1111
- type: map
1212
mapping:
1313

14-
# The path to the patch file, relative to the root of the module
14+
# The path to the patch file, relative to patch-base
1515
# E.g. zephyr/kernel-pipe-fix-not-k-no-wait-and-ge-min-xfer-bytes.patch
1616
path:
1717
required: true

scripts/west_commands/patch.py

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import re
99
import shlex
1010
import subprocess
11+
import sys
1112
import textwrap
1213
import urllib.request
1314
from pathlib import Path
@@ -16,6 +17,10 @@
1617
import yaml
1718
from west.commands import WestCommand
1819

20+
sys.path.append(os.fspath(Path(__file__).parent.parent))
21+
import zephyr_module
22+
from zephyr_ext_common import ZEPHYR_BASE
23+
1924
try:
2025
from yaml import CSafeDumper as SafeDumper
2126
from yaml import CSafeLoader as SafeLoader
@@ -29,9 +34,6 @@
2934
WEST_PATCH_BASE = Path("zephyr") / "patches"
3035
WEST_PATCH_YAML = Path("zephyr") / "patches.yml"
3136

32-
_WEST_MANIFEST_DIR = Path("WEST_MANIFEST_DIR")
33-
_WEST_TOPDIR = Path("WEST_TOPDIR")
34-
3537

3638
class Patch(WestCommand):
3739
def __init__(self):
@@ -101,38 +103,50 @@ def do_add_parser(self, parser_adder):
101103
parser.add_argument(
102104
"-b",
103105
"--patch-base",
104-
help="Directory containing patch files",
106+
help=f"""
107+
Directory containing patch files (absolute or relative to module dir,
108+
default: {WEST_PATCH_BASE})""",
105109
metavar="DIR",
106-
default=_WEST_MANIFEST_DIR / WEST_PATCH_BASE,
107110
type=Path,
108111
)
109112
parser.add_argument(
110113
"-l",
111114
"--patch-yml",
112-
help="Path to patches.yml file",
115+
help=f"""
116+
Path to patches.yml file (absolute or relative to module dir,
117+
default: {WEST_PATCH_YAML})""",
113118
metavar="FILE",
114-
default=_WEST_MANIFEST_DIR / WEST_PATCH_YAML,
115119
type=Path,
116120
)
117121
parser.add_argument(
118122
"-w",
119123
"--west-workspace",
120124
help="West workspace",
121125
metavar="DIR",
122-
default=_WEST_TOPDIR,
123126
type=Path,
124127
)
125128
parser.add_argument(
126-
"-m",
127-
"--module",
129+
"-sm",
130+
"--src-module",
131+
dest="src_module",
132+
metavar="MODULE",
133+
type=str,
134+
help="""
135+
Zephyr module containing the patch definition (name, absolute path or
136+
path relative to west-workspace)""",
137+
)
138+
parser.add_argument(
139+
"-dm",
140+
"--dst-module",
128141
action="append",
129-
dest="modules",
130-
metavar="DIR",
131-
type=Path,
132-
help="Zephyr module directory to run the 'patch' command for. "
133-
"Option can be passed multiple times. "
134-
"If this option is not given, the 'patch' command will run for Zephyr "
135-
"and all modules.",
142+
dest="dst_modules",
143+
metavar="MODULE",
144+
type=str,
145+
help="""
146+
Zephyr module to run the 'patch' command for.
147+
Option can be passed multiple times.
148+
If this option is not given, the 'patch' command will run for Zephyr
149+
and all modules.""",
136150
)
137151

138152
subparsers = parser.add_subparsers(
@@ -257,14 +271,36 @@ def filter_args(self, args):
257271
self.die("could not retrieve manifest path from west configuration")
258272

259273
topdir = Path(self.topdir)
260-
manifest_dir = topdir / manifest_path
261274

262-
if args.patch_base.is_relative_to(_WEST_MANIFEST_DIR):
263-
args.patch_base = manifest_dir / args.patch_base.relative_to(_WEST_MANIFEST_DIR)
264-
if args.patch_yml.is_relative_to(_WEST_MANIFEST_DIR):
265-
args.patch_yml = manifest_dir / args.patch_yml.relative_to(_WEST_MANIFEST_DIR)
266-
if args.west_workspace.is_relative_to(_WEST_TOPDIR):
267-
args.west_workspace = topdir / args.west_workspace.relative_to(_WEST_TOPDIR)
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')
279+
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")
281+
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
284+
else:
285+
manifest_dir = topdir / manifest_path
286+
287+
if args.patch_base is None:
288+
args.patch_base = manifest_dir / WEST_PATCH_BASE
289+
if not args.patch_base.is_absolute():
290+
args.patch_base = manifest_dir / args.patch_base
291+
292+
if args.patch_yml is None:
293+
args.patch_yml = manifest_dir / WEST_PATCH_YAML
294+
elif not args.patch_yml.is_absolute():
295+
args.patch_yml = manifest_dir / args.patch_yml
296+
297+
if args.west_workspace is None:
298+
args.west_workspace = topdir
299+
elif not args.west_workspace.is_absolute():
300+
args.west_workspace = topdir / args.west_workspace
301+
302+
if args.dst_modules is not None:
303+
args.dst_modules = [self.get_module_path(m) for m in args.dst_modules]
268304

269305
def load_yml(self, args, allow_missing):
270306
if not os.path.isfile(args.patch_yml):
@@ -303,9 +339,9 @@ def do_run(self, args, _):
303339
"gh-fetch": self.gh_fetch,
304340
}
305341

306-
method[args.subcommand](args, yml, args.modules)
342+
method[args.subcommand](args, yml, args.dst_modules)
307343

308-
def apply(self, args, yml, mods=None):
344+
def apply(self, args, yml, dst_mods=None):
309345
patches = yml.get("patches", [])
310346
if not patches:
311347
return
@@ -315,8 +351,11 @@ def apply(self, args, yml, mods=None):
315351
patched_mods = set()
316352

317353
for patch_info in patches:
318-
mod = Path(patch_info["module"])
319-
if mods and mod not in mods:
354+
mod = self.get_module_path(patch_info["module"])
355+
if mod is None:
356+
continue
357+
358+
if dst_mods and mod not in dst_mods:
320359
continue
321360

322361
pth = patch_info["path"]
@@ -377,7 +416,7 @@ def apply(self, args, yml, mods=None):
377416

378417
self.die(f"failed to apply patch {failed_patch}")
379418

380-
def clean(self, args, yml, mods=None):
419+
def clean(self, args, yml, dst_mods=None):
381420
clean_cmd = yml["clean-command"]
382421
checkout_cmd = yml["checkout-command"]
383422

@@ -388,9 +427,14 @@ def clean(self, args, yml, mods=None):
388427
clean_cmd_list = shlex.split(clean_cmd)
389428
checkout_cmd_list = shlex.split(checkout_cmd)
390429

391-
for mod, mod_path in Patch.get_mod_paths(args, yml).items():
392-
if mods and mod not in mods:
430+
for mod in yml.get("patches", []):
431+
m = self.get_module_path(mod.get("module"))
432+
if m is None:
433+
continue
434+
if dst_mods and m not in dst_mods:
393435
continue
436+
mod_path = Path(args.west_workspace) / m
437+
394438
try:
395439
if checkout_cmd:
396440
self.dbg(f"Running '{checkout_cmd}' in {mod}.. ", end="")
@@ -414,13 +458,13 @@ def clean(self, args, yml, mods=None):
414458
# If this fails for some reason, just log it and continue
415459
self.err(f"failed to clean up {mod}: {e}")
416460

417-
def list(self, args, yml, mods=None):
461+
def list(self, args, yml, dst_mods=None):
418462
patches = yml.get("patches", [])
419463
if not patches:
420464
return
421465

422466
for patch_info in patches:
423-
if mods and Path(patch_info["module"]) not in mods:
467+
if dst_mods and self.get_module_path(patch_info["module"]) not in dst_mods:
424468
continue
425469
self.inf(patch_info)
426470

@@ -490,16 +534,23 @@ def get_file_sha256sum(filename: Path) -> str:
490534

491535
return digest.hexdigest()
492536

493-
@staticmethod
494-
def get_mod_paths(args, yml):
495-
patches = yml.get("patches", [])
496-
if not patches:
497-
return {}
537+
def get_module_path(self, module_name_or_path):
538+
if module_name_or_path is None:
539+
return None
498540

499-
mod_paths = {}
500-
for patch_info in patches:
501-
mod = Path(patch_info["module"])
502-
mod_path = os.path.realpath(Path(args.west_workspace) / mod)
503-
mod_paths[mod] = mod_path
541+
topdir = Path(self.topdir)
542+
543+
if Path(module_name_or_path).is_absolute():
544+
if Path(module_name_or_path).is_dir():
545+
return Path(module_name_or_path).resolve().relative_to(topdir)
546+
return None
547+
548+
if (topdir / module_name_or_path).is_dir():
549+
return Path(module_name_or_path)
550+
551+
all_modules = zephyr_module.parse_modules(ZEPHYR_BASE, self.manifest)
552+
for m in all_modules:
553+
if m.meta['name'] == module_name_or_path:
554+
return Path(m.project).relative_to(topdir)
504555

505-
return mod_paths
556+
return None

0 commit comments

Comments
 (0)