5c97379765
date: 2026-08-01T16:05:18 master commit: 3a05c03079d796f533f342489b3f681cfd21f98d
93 lines
3.0 KiB
Python
Executable File
93 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import importlib
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
generator_path = os.path.dirname(os.path.realpath(__file__))
|
|
include_pattern = re.compile(r'CM_ "IMPORT (.*?)";\n')
|
|
|
|
|
|
def _read_dbc(src_dir: str, filename: str, extra_files: dict[str, str] | None = None) -> str:
|
|
if extra_files and filename in extra_files:
|
|
return extra_files[filename]
|
|
with open(os.path.join(src_dir, filename), encoding='utf-8') as file_in:
|
|
return file_in.read()
|
|
|
|
|
|
def _create_dbc_content(src_dir: str, filename: str, extra_files: dict[str, str] | None = None) -> str:
|
|
dbc_file_in = _read_dbc(src_dir, filename, extra_files)
|
|
includes = include_pattern.findall(dbc_file_in)
|
|
|
|
parts = ['CM_ "AUTOGENERATED FILE, DO NOT EDIT";\n']
|
|
for include_filename in includes:
|
|
parts.append(f'\n\nCM_ "Imported file {include_filename} starts here";\n')
|
|
parts.append(_read_dbc(src_dir, include_filename, extra_files))
|
|
|
|
parts.append(f'\nCM_ "{filename} starts here";\n')
|
|
core_dbc = include_pattern.sub('', dbc_file_in)
|
|
parts.append(core_dbc)
|
|
|
|
return ''.join(parts)
|
|
|
|
|
|
def _collect_script_outputs() -> dict[str, dict[str, str]]:
|
|
"""Import and call generate() from each sub-generator script.
|
|
Returns {dir_name: {filename: content}}."""
|
|
outputs: dict[str, dict[str, str]] = {}
|
|
|
|
for py_file in sorted(Path(generator_path).rglob("*.py")):
|
|
if py_file.name.startswith("test_") or py_file.name == "generator.py":
|
|
continue
|
|
|
|
dir_name = py_file.parent.name
|
|
module_name = f"opendbc.dbc.generator.{dir_name}.{py_file.stem}"
|
|
mod = importlib.import_module(module_name)
|
|
if hasattr(mod, 'generate'):
|
|
outputs.setdefault(dir_name, {}).update(mod.generate())
|
|
|
|
return outputs
|
|
|
|
|
|
def generate_all() -> dict[str, str]:
|
|
"""Generate all DBC content in memory. Returns {name: content} where name has no .dbc extension."""
|
|
script_outputs = _collect_script_outputs()
|
|
|
|
result = {}
|
|
for src_dir, _, filenames in os.walk(generator_path):
|
|
if src_dir == generator_path:
|
|
continue
|
|
|
|
dir_name = os.path.basename(src_dir)
|
|
extra = script_outputs.get(dir_name, {})
|
|
|
|
# all non-_ .dbc files: on-disk templates + script-generated
|
|
all_dbc_files = {f for f in filenames if f.endswith('.dbc') and not f.startswith('_')}
|
|
all_dbc_files |= {f for f in extra if not f.startswith('_')}
|
|
|
|
for filename in sorted(all_dbc_files):
|
|
output_name = filename.replace('.dbc', '_generated')
|
|
content = _create_dbc_content(src_dir, filename, extra)
|
|
result[output_name] = content
|
|
|
|
return result
|
|
|
|
|
|
def create_all(output_path: str):
|
|
"""Generate all DBC files and write them to output_path (for backward compatibility)."""
|
|
import glob
|
|
generated_suffix = '_generated.dbc'
|
|
|
|
# clear out old generated DBCs
|
|
for f in glob.glob(os.path.join(output_path, f"*{generated_suffix}")):
|
|
os.remove(f)
|
|
|
|
for name, content in generate_all().items():
|
|
with open(os.path.join(output_path, name + '.dbc'), 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
opendbc_root = os.path.join(generator_path, '../')
|
|
create_all(opendbc_root)
|