Files
IronOS/source/Settings/generate_settings.py
2025-07-17 18:29:37 +10:00

147 lines
4.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""
IronOS Settings Generator - Refactored
A tool to generate C++ code from settings definitions for IronOS.
This is a refactored version that uses the shared library modules.
"""
import yaml
import os
import sys
import argparse
from typing import List
# Import from the lib package
from lib.settings_model import Settings
from lib.settings_types import DEFAULT_YAML_PATH
# Constants
SETTINGS_TEMPLATE_PATH = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "settings_gen.cpp.template"
)
def parse_arguments() -> tuple[str, str, str]:
"""Parse command line arguments for the settings generator
Returns:
tuple: (model_code, settings_definitions_path, output_file_path)
"""
parser = argparse.ArgumentParser(
description="Processes the settings definitions and makes a compilable C++ file."
)
parser.add_argument(
"model_code", help="Model code identifier (e.g., TS101, Pinecilv2)"
)
parser.add_argument(
"settings_definitions",
help="Path to the settings YAML definition file",
default=DEFAULT_YAML_PATH,
nargs="?",
)
parser.add_argument(
"output_file_path", help="Path where the generated C++ file should be written"
)
print(f"Parsing command line arguments... {sys.argv[1:]}")
if len(sys.argv) < 3:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
# Check if settings definitions file exists
if not os.path.isfile(args.settings_definitions):
print(
f"Error: Settings definition file '{args.settings_definitions}' does not exist."
)
parser.print_help()
sys.exit(1)
return (args.model_code, args.settings_definitions, args.output_file_path)
def convert_settings_to_cpp(settings) -> str:
"""Convert settings to C++ code for inclusion in a template
Args:
settings: Either a Settings object or a dictionary with settings data
Returns:
String containing formatted C++ code for settings table
"""
cpp_code = ""
# Handle both our Settings object format and the original dictionary format
if hasattr(settings, "entries"):
# New format: Settings object with entries attribute
for entry in settings.entries:
cpp_code += f" {{ {entry.min:>22}, {entry.max:>70}, {entry.increment:>18}, {entry.default:>29}}}, // {entry.name}\r\n"
else:
# Original format: Dictionary with 'settings' key
for setting in settings.settings:
cpp_code += f" {{ {setting['min']:>22}, {setting['max']:>70}, {setting['increment']:>18}, {setting['default']:>29}}}, // {setting['name']}\r\n"
return cpp_code
def main():
"""Main function to run the settings generator"""
# Parse command line arguments
(model_code, settings_definitions_path, settings_output_path) = parse_arguments()
# Initialize settings
settings = Settings()
# Load settings definitions from YAML
print(f"Loading settings definitions from {settings_definitions_path}")
try:
settings.load_from_yaml(settings_definitions_path)
except Exception as e:
print(f"Error loading settings definitions: {e}")
# Fall back to the original loading method if the new one fails
try:
print("Trying alternative loading method...")
# Load using the original method from generate_settings.py
with open(settings_definitions_path, "r") as f:
data = yaml.safe_load(f)
settings = type("Settings", (), {})()
settings.settings = data["settings"]
print("Successfully loaded settings using alternative method.")
except Exception as nested_e:
print(f"All loading methods failed: {nested_e}")
sys.exit(1)
# Convert settings to C++ code
cpp_code = convert_settings_to_cpp(settings)
# Load template content
try:
with open(SETTINGS_TEMPLATE_PATH, "r") as f:
template_content = f.read()
except Exception as e:
print(f"Error reading template file: {e}")
sys.exit(1)
# Write the generated C++ code to the output file
try:
# Make sure the directory exists
os.makedirs(os.path.dirname(settings_output_path), exist_ok=True)
# Write the output file
with open(settings_output_path, "w") as f:
f.write(template_content.replace("$SETTINGSTABLE", cpp_code))
print(f"Successfully generated C++ code at {settings_output_path}")
except Exception as e:
print(f"Error writing output file: {e}")
sys.exit(1)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nOperation cancelled by user")
sys.exit(1)