🔨 Fix and improve schema.py (#28228)

This commit is contained in:
Andrew 2025-12-16 00:34:18 -05:00 committed by GitHub
parent c39f32c542
commit 54dfe6237c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -61,8 +61,7 @@ def find_grouping(gdict, filekey, sectkey, optkey, pindex):
optparts[pindex] = '*'
wildkey = '_'.join(optparts)
kkey = f'{filekey}|{sectkey}|{wildkey}'
if kkey not in gdict: gdict[kkey] = []
gdict[kkey].append((subkey, modkey))
gdict.setdefault(kkey, []).append((subkey, modkey))
# Build a list of potential groups. Only those with multiple items will be grouped.
def group_options(schema):
@ -137,7 +136,9 @@ def extract_files(filekey):
# Regex for #define NAME [VALUE] [COMMENT] with sanitized line
defgrep = re.compile(r'^(//)?\s*(#define)\s+([A-Za-z0-9_]+)\s*(.*?)\s*(//.+)?$')
# Pattern to match a float value
flt = r'[-+]?\s*(\d+\.|\d*\.\d+)([eE][-+]?\d+)?[fF]?'
flt = r'[-+]?\s*(?:\d+\.|\d*\.\d+)(?:[eE][-+]?\d+)?[fF]?'
# Pattern to match an integer expression
int_expr = r'(?:[-+]?\s*\d+(?:\s*[*\/+\-]\s*\d+)*)'
# Start with unknown state
state = Parse.NORMAL
# Serial ID
@ -314,9 +315,11 @@ def extract_files(filekey):
# Parenthesize the given expression if needed
def atomize(s):
if s == '' \
or re.match(r'^[A-Za-z0-9_]*(\([^)]+\))?$', s) \
or re.match(r'^[A-Za-z0-9_]+ == \d+?$', s):
s = s.strip()
if not s or s.isidentifier() or (s.startswith('(') and s.endswith(')')):
return s
if re.match(r'^[A-Za-z0-9_]*(\([^)]+\))$', s) \
or re.match(r'^[A-Za-z0-9_]+\s*[=!<>]=?\s*.*$', s):
return s
return f'({s})'
@ -369,27 +372,30 @@ def extract_files(filekey):
}
# Type is based on the value
value_type = \
'switch' if val == '' \
else 'int' if re.match(r'^[-+]?\s*\d+$', val) \
else 'ints' if re.match(r'^([-+]?\s*\d+)(\s*,\s*[-+]?\s*\d+)+$', val) \
else 'floats' if re.match(rf'({flt}(\s*,\s*{flt})+)', val) \
else 'float' if re.match(f'^({flt})$', val) \
else 'string' if val[0] == '"' \
else 'char' if val[0] == "'" \
else 'bool' if val in ('true', 'false') \
else 'state' if val in ('HIGH', 'LOW') \
else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val) \
else 'int[]' if re.match(r'^{\s*[-+]?\s*\d+(\s*,\s*[-+]?\s*\d+)*\s*}$', val) \
else 'float[]' if re.match(r'^{{\s*{flt}(\s*,\s*{flt})*\s*}}$', val) \
else 'array' if val[0] == '{' \
else ''
value_type = (
'switch' if val == ''
else 'int' if re.match(r'^[-+]?\s*\d+$', val)
else 'ints' if re.match(r'^[-+]?\s*\d+(?:\s*,\s*[-+]?\s*\d+)+$', val)
else 'floats' if re.match(rf"^{flt}(?:\s*,\s*{flt})+$", val)
else 'float' if re.match(rf"^{flt}$", val)
else 'string' if val.startswith('"')
else 'char' if val.startswith("'")
else 'bool' if val in ('true', 'false')
else 'state' if val in ('HIGH', 'LOW')
else 'int[]' if re.match(rf"^\{{\s*{int_expr}(?:\s*,\s*{int_expr})*\s*\}}$", val)
else 'float[]' if re.match(rf"^\{{\s*{flt}(?:\s*,\s*{flt})*\s*\}}$", val)
else 'array' if val.startswith('{')
else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val)
else ''
)
val = (val == 'true') if value_type == 'bool' \
else int(val) if value_type == 'int' \
else val.replace('f','') if value_type == 'floats' \
else float(val.replace('f','')) if value_type == 'float' \
else val
val = (
(val == 'true') if value_type == 'bool'
else int(val) if value_type == 'int'
else val.replace('f','') if value_type == 'floats'
else float(val.replace('f','')) if value_type == 'float'
else val
)
if val != '': define_info['value'] = val
if value_type != '': define_info['type'] = value_type
@ -496,9 +502,14 @@ def main():
unk = not inargs(['some','json','jsons','group','yml','yaml', '-h', '--help'])
if (unk): print(f"Unknown option: '{args[0]}'")
if inargs(['-h', '--help']) or unk:
print("Extract firmware configuration into structured JSON or YAML schema format.")
print("Usage: schema.py [-h] [some|json|jsons|group|yml|yaml]")
print(" some = json + yml")
print(" jsons = json + group")
print(" some Generate both JSON and YAML output (schema.json and schema.yml)")
print(" json Generate JSON output (schema.json)")
print(" jsons Generate grouped JSON output with wildcard options (schema.json and schema_grouped.json)")
print(" group Generate grouped JSON output only (schema_grouped.json)")
print(" yml Generate YAML output (schema.yml)")
print(" yaml Same as 'yml'")
return
# JSON schema