blob: d501416f54014fcab88ca55dd1cc31a440500c4b [file] [log] [blame]
Carles Cufi336aa9d2022-08-04 19:08:22 +02001# Copyright (c) 2022 Nordic Semiconductor ASA
2#
3# SPDX-License-Identifier: Apache-2.0
4
5import argparse
Carles Cufi336aa9d2022-08-04 19:08:22 +02006import os
7from pathlib import Path
8import sys
9import textwrap
10from urllib.parse import urlparse
11
12from west import log
13from west.commands import WestCommand
14
15from zephyr_ext_common import ZEPHYR_BASE
16
17sys.path.append(os.fspath(Path(__file__).parent.parent))
18import zephyr_module
19
20class Blobs(WestCommand):
21
Martí Bolívare04487c2022-08-18 18:25:02 -070022 DEFAULT_LIST_FMT = '{module} {status} {path} {type} {abspath}'
23
Carles Cufi336aa9d2022-08-04 19:08:22 +020024 def __init__(self):
25 super().__init__(
26 'blobs',
27 # Keep this in sync with the string in west-commands.yml.
28 'work with binary blobs',
29 'Work with binary blobs',
30 accepts_unknown_args=False)
31
32 def do_add_parser(self, parser_adder):
Carles Cufi336aa9d2022-08-04 19:08:22 +020033 parser = parser_adder.add_parser(
34 self.name,
35 help=self.help,
36 formatter_class=argparse.RawDescriptionHelpFormatter,
37 description=self.description,
38 epilog=textwrap.dedent(f'''\
39 FORMAT STRINGS
40 --------------
41
42 Blobs are listed using a Python 3 format string. Arguments
43 to the format string are accessed by name.
44
45 The default format string is:
46
Martí Bolívare04487c2022-08-18 18:25:02 -070047 "{self.DEFAULT_LIST_FMT}"
Carles Cufi336aa9d2022-08-04 19:08:22 +020048
49 The following arguments are available:
50
51 - module: name of the module that contains this blob
52 - abspath: blob absolute path
53 - status: short status (A: present, M: hash failure, D: not present)
54 - path: blob local path from <module>/zephyr/blobs/
55 - sha256: blob SHA256 hash in hex
56 - type: type of blob
57 - version: version string
58 - license_path: path to the license file for the blob
59 - uri: URI to the remote location of the blob
60 - description: blob text description
61 - doc-url: URL to the documentation for this blob
62 '''))
63
64 # Remember to update west-completion.bash if you add or remove
65 # flags
Carles Cufi5524f7a2022-08-17 13:48:13 +020066 parser.add_argument('subcmd', nargs=1,
67 choices=['list', 'fetch', 'clean'],
Martí Bolívar3b84dff2022-08-18 18:15:34 -070068 help='sub-command to execute')
Carles Cufi336aa9d2022-08-04 19:08:22 +020069
Carles Cufi02c95c62022-08-16 19:02:43 +020070 parser.add_argument('modules', metavar='MODULE', nargs='*',
Martí Bolívara3f4edb2022-08-18 18:18:03 -070071 help='''zephyr modules to operate on;
72 all modules will be used if not given''')
Carles Cufi336aa9d2022-08-04 19:08:22 +020073
Martí Bolívare04487c2022-08-18 18:25:02 -070074 group = parser.add_argument_group('west blob list options')
75 group.add_argument('-f', '--format',
76 help='''format string to use to list each blob;
77 see FORMAT STRINGS below''')
78
Carles Cufi336aa9d2022-08-04 19:08:22 +020079 return parser
80
Carles Cufi336aa9d2022-08-04 19:08:22 +020081 def get_blobs(self, args):
82 blobs = []
83 modules = args.modules
84 for module in zephyr_module.parse_modules(ZEPHYR_BASE, self.manifest):
Carles Cufi336aa9d2022-08-04 19:08:22 +020085 # Filter by module
86 module_name = module.meta.get('name', None)
Carles Cufi389af082022-08-16 16:56:59 +020087 if len(modules) and module_name not in modules:
Carles Cufi336aa9d2022-08-04 19:08:22 +020088 continue
89
Carles Cufib662bc92022-08-24 15:42:55 +020090 blobs += zephyr_module.process_blobs(module.project, module.meta)
Carles Cufi336aa9d2022-08-04 19:08:22 +020091
92 return blobs
93
94 def list(self, args):
95 blobs = self.get_blobs(args)
Carles Cufi25db5342022-08-24 16:44:14 +020096 fmt = args.format or self.DEFAULT_LIST_FMT
Carles Cufi336aa9d2022-08-04 19:08:22 +020097 for blob in blobs:
Martí Bolívare04487c2022-08-18 18:25:02 -070098 log.inf(fmt.format(**blob))
Carles Cufi336aa9d2022-08-04 19:08:22 +020099
Carles Cufi04245092022-08-17 15:06:17 +0200100 def ensure_folder(self, path):
101 path.parent.mkdir(parents=True, exist_ok=True)
102
Carles Cufi336aa9d2022-08-04 19:08:22 +0200103 def fetch_blob(self, url, path):
104 scheme = urlparse(url).scheme
105 log.dbg(f'Fetching {path} with {scheme}')
106 import fetchers
107 fetcher = fetchers.get_fetcher_cls(scheme)
108
109 log.dbg(f'Found fetcher: {fetcher}')
110 inst = fetcher()
Carles Cufi04245092022-08-17 15:06:17 +0200111 self.ensure_folder(path)
Carles Cufi336aa9d2022-08-04 19:08:22 +0200112 inst.fetch(url, path)
113
114 def fetch(self, args):
115 blobs = self.get_blobs(args)
116 for blob in blobs:
117 if blob['status'] == 'A':
Martí Bolívar21214cc2022-08-18 18:25:47 -0700118 log.dbg('Blob {module}: {abspath} is up to date'.format(**blob))
Carles Cufi336aa9d2022-08-04 19:08:22 +0200119 continue
Carles Cufi5524f7a2022-08-17 13:48:13 +0200120 log.inf('Fetching blob {module}: {abspath}'.format(**blob))
Carles Cufi336aa9d2022-08-04 19:08:22 +0200121 self.fetch_blob(blob['url'], blob['abspath'])
122
Carles Cufi5524f7a2022-08-17 13:48:13 +0200123 def clean(self, args):
124 blobs = self.get_blobs(args)
125 for blob in blobs:
126 if blob['status'] == 'D':
Martí Bolívar21214cc2022-08-18 18:25:47 -0700127 log.dbg('Blob {module}: {abspath} not in filesystem'.format(**blob))
Carles Cufi5524f7a2022-08-17 13:48:13 +0200128 continue
129 log.inf('Deleting blob {module}: {status} {abspath}'.format(**blob))
130 blob['abspath'].unlink()
Carles Cufi336aa9d2022-08-04 19:08:22 +0200131
132 def do_run(self, args, _):
Carles Cufif0330402022-08-24 15:51:44 +0200133 log.dbg(f'subcmd: \'{args.subcmd[0]}\' modules: {args.modules}')
Carles Cufi336aa9d2022-08-04 19:08:22 +0200134
135 subcmd = getattr(self, args.subcmd[0])
Martí Bolívare04487c2022-08-18 18:25:02 -0700136
Carles Cufif0330402022-08-24 15:51:44 +0200137 if args.subcmd[0] != 'list' and args.format is not None:
Martí Bolívare04487c2022-08-18 18:25:02 -0700138 log.die(f'unexpected --format argument; this is a "west blobs list" option')
139
Carles Cufi336aa9d2022-08-04 19:08:22 +0200140 subcmd(args)