Files
chuan 5d725e40a9 fix: 修复外设传输与退出持久化并拆分运行脚本
- 修复 DMA 请求电平追踪、接收 FIFO 打包和禁用时的数据提交,更新 USART 的接收 DMA 请求
- 保留定时器复位前的 RCC 输入频率
- 正常退出时保存内部 Flash 已完成编程数据,过滤当前未完成编程字
- 使用独立进程组请求 Renode 正常退出,退出未完成时保留镜像锁和实例记录
- 将 controller.py 拆分为环境配置、Flash 镜像、进程管理和仿真启动模块,保留原命令入口
- 为 scripts 下的 Python 文件补充职责、生命周期和异常边界注释,并更新退出与持久化说明
2026-10-21 15:31:26 +08:00

66 lines
2.4 KiB
Python

"""读取和更新本地 .env 配置,不执行 Shell 表达式或展开变量"""
import json
import os
def read_env(path):
"""解析 KEY=value,支持引号内的空格与井号,格式错误时报告文件位置
仅整行井号作为注释,双引号值按 JSON 字符串解析,单引号值保持字面内容
"""
if not path.exists():
return {}
result = {}
for number, line in enumerate(path.read_text(encoding='utf-8-sig').splitlines(), 1):
line = line.strip()
if not line or line.startswith('#'):
continue
key, separator, value = line.partition('=')
key, value = key.strip(), value.strip()
if not separator or not key.isidentifier():
raise ValueError(f'{path}:{number}: expected KEY=value')
if value.startswith('"'):
value = json.loads(value)
elif value.startswith("'"):
if not value.endswith("'") or len(value) < 2:
raise ValueError(f'{path}:{number}: unterminated quoted value')
value = value[1:-1]
result[key] = value
return result
def get_setting(root, name, default):
"""依次采用进程环境变量、项目 .env 和调用方默认值"""
return os.environ.get(name, read_env(root / '.env').get(name, default))
def set_setting(root, name, value):
"""更新指定键的全部重复项,保留无关配置与注释,并转义写入的字符串"""
path = root / '.env'
lines = path.read_text(encoding='utf-8-sig').splitlines() if path.exists() else []
replacement = f'{name}={json.dumps(value, ensure_ascii=False)}'
matched = False
for index, line in enumerate(lines):
if line.partition('=')[0].strip() == name:
lines[index] = replacement
matched = True
if not matched:
lines.append(replacement)
path.write_text('\n'.join(lines) + '\n', encoding='utf-8')
def as_boolean(value):
"""仅接受约定的布尔字符串,避免拼写错误被静默解释为关闭"""
value = value.lower()
if value not in ('1', 'true', 'yes', 'on', '0', 'false', 'no', 'off'):
raise ValueError(f'Invalid boolean: {value}')
return value in ('1', 'true', 'yes', 'on')
def as_port(value):
"""转换并校验可显式绑定的 TCP 端口,不接受自动分配用的零值"""
port = int(value)
if not 1 <= port <= 65535:
raise ValueError(f'Invalid TCP port: {value}')
return port