2
2
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
3
3
4
4
from pathlib import Path
5
- import re
5
+ import json
6
6
import shutil
7
7
8
8
from jinja2 import Environment , FileSystemLoader
9
9
from west .commands import WestCommand
10
10
from west import log
11
11
from yaml import load
12
+ import jsonschema
12
13
13
14
try :
14
15
from yaml import CLoader as Loader
19
20
SCRIPT_DIR = Path (__file__ ).absolute ().parent
20
21
TEMPLATE_DIR = SCRIPT_DIR / "templates"
21
22
CONFIG = SCRIPT_DIR / "config.yml"
22
-
23
- VENDOR_RE = re .compile (r"^[a-zA-Z0-9_-]+$" )
24
- BOARD_RE = re .compile (r"^[a-zA-Z0-9_-]+$" )
23
+ SCHEMA = SCRIPT_DIR / "schema.json"
25
24
26
25
27
26
class NcsGenboard (WestCommand ):
@@ -36,31 +35,38 @@ def do_add_parser(self, parser_adder):
36
35
self .name , help = self .help , description = self .description
37
36
)
38
37
39
- parser .add_argument (
40
- "-o" , "--output" , required = True , type = Path , help = "Output directory"
38
+ group = parser .add_mutually_exclusive_group (required = True )
39
+ group .add_argument (
40
+ "-s" , "--json-schema" , action = "store_true" , help = "Provide JSON schema"
41
41
)
42
- parser .add_argument ("-e" , "--vendor" , required = True , help = "Vendor name" )
43
- parser .add_argument ("-b" , "--board" , required = True , help = "Board name" )
44
- parser .add_argument (
45
- "-d" , "--board-desc" , required = True , help = "Board description"
42
+ group .add_argument (
43
+ "-r" , "--json-schema-response" , type = str , help = "JSON schema response"
46
44
)
47
- parser .add_argument ("-s" , "--soc" , required = True , help = "SoC" )
48
- parser .add_argument ("-v" , "--variant" , required = True , help = "Variant" )
49
45
50
46
return parser
51
47
52
48
def do_run (self , args , unknown_args ):
49
+ with open (SCHEMA , "r" ) as f :
50
+ schema = json .loads (f .read ())
51
+
52
+ if args .json_schema :
53
+ print (json .dumps (schema ))
54
+ return
55
+
53
56
with open (CONFIG , "r" ) as f :
54
57
config = load (f , Loader = Loader )
55
58
56
59
# validate input
57
- if not VENDOR_RE .match (args .vendor ):
58
- log .err (f"Invalid vendor name: { args .vendor } " )
59
- return
60
+ input = json .loads (args .json_schema_response )
60
61
61
- if not BOARD_RE .match (args .board ):
62
- log .err (f"Invalid board name: { args .board } " )
63
- return
62
+ try :
63
+ jsonschema .validate (input , schema )
64
+ except jsonschema .ValidationError as e :
65
+ raise Exception ("Board configuration is not valid" ) from e
66
+
67
+ soc_parts = input ["soc" ].split ("-" )
68
+ req_soc = soc_parts [0 ].lower ()
69
+ req_variant = soc_parts [1 ].lower ()
64
70
65
71
series = None
66
72
soc = None
@@ -69,18 +75,18 @@ def do_run(self, args, unknown_args):
69
75
break
70
76
71
77
for soc_ in product ["socs" ]:
72
- if args . soc == soc_ ["name" ]:
78
+ if req_soc == soc_ ["name" ]:
73
79
series = product ["series" ]
74
80
soc = soc_
75
81
break
76
82
77
83
if not series :
78
- log .err (f"Invalid/unsupported SoC: { args . soc } " )
84
+ log .err (f"Invalid/unsupported SoC: { req_soc } " )
79
85
return
80
86
81
87
targets = []
82
88
for variant in soc ["variants" ]:
83
- if args . variant == variant ["name" ]:
89
+ if req_variant == variant ["name" ]:
84
90
if "cores" in variant :
85
91
for core in variant ["cores" ]:
86
92
target = {
@@ -119,7 +125,7 @@ def do_run(self, args, unknown_args):
119
125
break
120
126
121
127
if not targets :
122
- log .err (f"Invalid/unsupported variant: { args . variant } " )
128
+ log .err (f"Invalid/unsupported variant: { req_variant } " )
123
129
return
124
130
125
131
# prepare Jinja environment
@@ -129,16 +135,16 @@ def do_run(self, args, unknown_args):
129
135
loader = FileSystemLoader (TEMPLATE_DIR / series ),
130
136
)
131
137
132
- env .globals ["vendor" ] = args . vendor
133
- env .globals ["board" ] = args . board
134
- env .globals ["board_desc" ] = args . board_desc
138
+ env .globals ["vendor" ] = input [ " vendor" ]
139
+ env .globals ["board" ] = input [ " board" ]
140
+ env .globals ["board_desc" ] = input [ "description" ]
135
141
env .globals ["series" ] = series
136
- env .globals ["soc" ] = args . soc
137
- env .globals ["variant" ] = args . variant
142
+ env .globals ["soc" ] = req_soc
143
+ env .globals ["variant" ] = req_variant
138
144
env .globals ["targets" ] = targets
139
145
140
146
# render templates/copy files
141
- out_dir = args . output / args . vendor / args . board
147
+ out_dir = Path ( input [ "root" ]) / "boards" / input [ " vendor" ] / input [ " board" ]
142
148
if not out_dir .exists ():
143
149
out_dir .mkdir (parents = True )
144
150
@@ -147,14 +153,14 @@ def do_run(self, args, unknown_args):
147
153
shutil .copy (tmpl , out_dir )
148
154
149
155
tmpl = TEMPLATE_DIR / series / "board-pinctrl.dtsi"
150
- shutil .copy (tmpl , out_dir / f"{ args . board } -pinctrl.dtsi" )
156
+ shutil .copy (tmpl , out_dir / f"{ input [ ' board' ] } -pinctrl.dtsi" )
151
157
152
158
tmpl = env .get_template ("board.cmake.jinja2" )
153
159
with open (out_dir / "board.cmake" , "w" ) as f :
154
160
f .write (tmpl .render ())
155
161
156
162
tmpl = env .get_template ("Kconfig.board.jinja2" )
157
- with open (out_dir / f"Kconfig.{ args . board } " , "w" ) as f :
163
+ with open (out_dir / f"Kconfig.{ input [ ' board' ] } " , "w" ) as f :
158
164
f .write (tmpl .render ())
159
165
160
166
tmpl = env .get_template ("board.yml.jinja2" )
@@ -168,23 +174,23 @@ def do_run(self, args, unknown_args):
168
174
# nrf53 specific files
169
175
if series == "nrf53" :
170
176
tmpl = env .get_template ("board-cpuapp_partitioning.dtsi.jinja2" )
171
- with open (out_dir / f"{ args . board } -cpuapp_partitioning.dtsi" , "w" ) as f :
177
+ with open (out_dir / f"{ input [ ' board' ] } -cpuapp_partitioning.dtsi" , "w" ) as f :
172
178
f .write (tmpl .render (config ))
173
179
174
180
tmpl = TEMPLATE_DIR / series / "board-shared_sram.dtsi"
175
- shutil .copy (tmpl , out_dir / f"{ args . board } -shared_sram.dtsi" )
181
+ shutil .copy (tmpl , out_dir / f"{ input [ ' board' ] } -shared_sram.dtsi" )
176
182
177
183
# nrf91 specific files
178
184
if series == "nrf91" :
179
185
tmpl = env .get_template ("board-partitioning.dtsi.jinja2" )
180
- with open (out_dir / f"{ args . board } -partitioning.dtsi" , "w" ) as f :
186
+ with open (out_dir / f"{ input [ ' board' ] } -partitioning.dtsi" , "w" ) as f :
181
187
f .write (tmpl .render (config ))
182
188
183
189
# per-target files
184
190
for target in targets :
185
- name = args . board
191
+ name = input [ " board" ]
186
192
if target .get ("core" ):
187
- name += f"_{ args . soc } _{ target ['core' ]} "
193
+ name += f"_{ req_soc } _{ target ['core' ]} "
188
194
if target ["ns" ]:
189
195
name += "_ns"
190
196
if target ["xip" ]:
@@ -201,3 +207,5 @@ def do_run(self, args, unknown_args):
201
207
tmpl = env .get_template ("board_twister.yml.jinja2" )
202
208
with open (out_dir / f"{ name } .yml" , "w" ) as f :
203
209
f .write (tmpl .render (target = target ))
210
+
211
+ print (f"Board { input ['board' ]} generated successfully" )
0 commit comments