8
8
import re
9
9
import shlex
10
10
import subprocess
11
+ import sys
11
12
import textwrap
12
13
import urllib .request
13
14
from pathlib import Path
16
17
import yaml
17
18
from west .commands import WestCommand
18
19
20
+ sys .path .append (os .fspath (Path (__file__ ).parent .parent ))
21
+ import zephyr_module
22
+ from zephyr_ext_common import ZEPHYR_BASE
23
+
19
24
try :
20
25
from yaml import CSafeDumper as SafeDumper
21
26
from yaml import CSafeLoader as SafeLoader
29
34
WEST_PATCH_BASE = Path ("zephyr" ) / "patches"
30
35
WEST_PATCH_YAML = Path ("zephyr" ) / "patches.yml"
31
36
32
- _WEST_MANIFEST_DIR = Path ("WEST_MANIFEST_DIR" )
33
- _WEST_TOPDIR = Path ("WEST_TOPDIR" )
34
-
35
37
36
38
class Patch (WestCommand ):
37
39
def __init__ (self ):
@@ -101,38 +103,50 @@ def do_add_parser(self, parser_adder):
101
103
parser .add_argument (
102
104
"-b" ,
103
105
"--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 } )""" ,
105
109
metavar = "DIR" ,
106
- default = _WEST_MANIFEST_DIR / WEST_PATCH_BASE ,
107
110
type = Path ,
108
111
)
109
112
parser .add_argument (
110
113
"-l" ,
111
114
"--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 } )""" ,
113
118
metavar = "FILE" ,
114
- default = _WEST_MANIFEST_DIR / WEST_PATCH_YAML ,
115
119
type = Path ,
116
120
)
117
121
parser .add_argument (
118
122
"-w" ,
119
123
"--west-workspace" ,
120
124
help = "West workspace" ,
121
125
metavar = "DIR" ,
122
- default = _WEST_TOPDIR ,
123
126
type = Path ,
124
127
)
125
128
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" ,
128
141
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.""" ,
136
150
)
137
151
138
152
subparsers = parser .add_subparsers (
@@ -257,14 +271,36 @@ def filter_args(self, args):
257
271
self .die ("could not retrieve manifest path from west configuration" )
258
272
259
273
topdir = Path (self .topdir )
260
- manifest_dir = topdir / manifest_path
261
274
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 ]
268
304
269
305
def load_yml (self , args , allow_missing ):
270
306
if not os .path .isfile (args .patch_yml ):
@@ -303,9 +339,9 @@ def do_run(self, args, _):
303
339
"gh-fetch" : self .gh_fetch ,
304
340
}
305
341
306
- method [args .subcommand ](args , yml , args .modules )
342
+ method [args .subcommand ](args , yml , args .dst_modules )
307
343
308
- def apply (self , args , yml , mods = None ):
344
+ def apply (self , args , yml , dst_mods = None ):
309
345
patches = yml .get ("patches" , [])
310
346
if not patches :
311
347
return
@@ -315,8 +351,11 @@ def apply(self, args, yml, mods=None):
315
351
patched_mods = set ()
316
352
317
353
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 :
320
359
continue
321
360
322
361
pth = patch_info ["path" ]
@@ -377,7 +416,7 @@ def apply(self, args, yml, mods=None):
377
416
378
417
self .die (f"failed to apply patch { failed_patch } " )
379
418
380
- def clean (self , args , yml , mods = None ):
419
+ def clean (self , args , yml , dst_mods = None ):
381
420
clean_cmd = yml ["clean-command" ]
382
421
checkout_cmd = yml ["checkout-command" ]
383
422
@@ -388,9 +427,14 @@ def clean(self, args, yml, mods=None):
388
427
clean_cmd_list = shlex .split (clean_cmd )
389
428
checkout_cmd_list = shlex .split (checkout_cmd )
390
429
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 :
393
435
continue
436
+ mod_path = Path (args .west_workspace ) / m
437
+
394
438
try :
395
439
if checkout_cmd :
396
440
self .dbg (f"Running '{ checkout_cmd } ' in { mod } .. " , end = "" )
@@ -414,13 +458,13 @@ def clean(self, args, yml, mods=None):
414
458
# If this fails for some reason, just log it and continue
415
459
self .err (f"failed to clean up { mod } : { e } " )
416
460
417
- def list (self , args , yml , mods = None ):
461
+ def list (self , args , yml , dst_mods = None ):
418
462
patches = yml .get ("patches" , [])
419
463
if not patches :
420
464
return
421
465
422
466
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 :
424
468
continue
425
469
self .inf (patch_info )
426
470
@@ -490,16 +534,23 @@ def get_file_sha256sum(filename: Path) -> str:
490
534
491
535
return digest .hexdigest ()
492
536
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
498
540
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 )
504
555
505
- return mod_paths
556
+ return None
0 commit comments