Files
MeshCore/scripts/client_acl_role.py
T
mikecarper c650278fa7 Share constrained STM32 code while preserving firmware features
Omit unbound forwarding-region callbacks only for exclusive Companion source roles. Reuse the compact neighbor sorter in repeaters for every RPC order and the CLI list, removing duplicate sort implementations while preserving storage and size gates.
2026-10-27 08:17:23 -07:00

93 lines
4.7 KiB
Python

"""Derive feature-preserving role definitions from effective application sources.
Shared compiler definitions cover application and helper translation units.
Unknown/custom roles keep the complete layout; room and sensor session fields
are never removed from builds that use them. Companions omit only unbound
forwarding-region callbacks because that role has no RegionMap.
"""
import importlib.util
from pathlib import Path
import re
SCRIPT_DIR = Path(__file__).resolve().parent if "__file__" in globals() else Path("scripts").resolve()
SPEC = importlib.util.spec_from_file_location("client_acl_source_policy", SCRIPT_DIR / "nrf52_flash_trim.py")
SOURCE_POLICY = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(SOURCE_POLICY)
DEFINITION = "MESH_CLIENT_REPEATER_ONLY"
REPEATER_SOURCES = ("../examples/simple_repeater/main.cpp", "../examples/simple_repeater/MyMesh.cpp")
OTHER_ROLES = ("simple_room_server", "simple_sensor", "companion_radio", "simple_secure_chat",
"kiss_modem", "partition_expander", "esp32_partition_migrator", "esp32_partition_legacy_seed")
COMPANION_DEFINITION = "MESH_ROLE_COMPANION"
COMPANION_SOURCES = ("../examples/companion_radio/main.cpp", "../examples/companion_radio/MyMesh.cpp")
def companion_role_policy(src_filter, flags=(), cppdefines=()):
"""Exclude unbound forwarding-scope callbacks, retaining all radio commands.
Companions have no RegionMap. Select the complete exclusive source role,
never an environment-name alias, so every translation unit shares its ABI.
Unknown and mixed roles retain the general callback implementation.
"""
values = SOURCE_POLICY.flag_defines(flags, cppdefines)
selected = SOURCE_POLICY.source_selected
other_roles = ("simple_repeater", *(role for role in OTHER_ROLES
if role != "companion_radio"))
filter_text = src_filter if isinstance(src_filter, str) else " ".join(map(str, src_filter))
example_includes = re.findall(r"\+<\.\./examples/([^>]+)>", filter_text.replace("\\", "/"))
known_companion_only = all(path == "companion_radio" or path.startswith("companion_radio/")
for path in example_includes)
qualified = (known_companion_only
and all(selected(src_filter, source) for source in COMPANION_SOURCES)
and not any(selected(src_filter, "../examples/" + role + "/" + source)
for role in other_roles
for source in ("main.cpp", "MyMesh.cpp", "SensorMesh.cpp")))
if COMPANION_DEFINITION in values:
value = values[COMPANION_DEFINITION]
text = "0" if value is None else str(value).strip("\"'() ")
if text not in ("0", "1"):
raise ValueError(COMPANION_DEFINITION + " override must be 0 or 1")
if text == "1" and not qualified:
raise ValueError(COMPANION_DEFINITION + "=1 requires only the Companion source role")
return {}
return {COMPANION_DEFINITION: 1} if qualified else {}
def role_policy(src_filter, flags=(), cppdefines=()):
values = SOURCE_POLICY.flag_defines(flags, cppdefines)
selected = SOURCE_POLICY.source_selected
qualified = (all(selected(src_filter, source) for source in REPEATER_SOURCES)
and not any(selected(src_filter, "../examples/" + role + "/main.cpp")
or selected(src_filter, "../examples/" + role + "/MyMesh.cpp")
or selected(src_filter, "../examples/" + role + "/SensorMesh.cpp")
for role in OTHER_ROLES)
and not any(name.startswith("COMPANION_") for name in values))
if DEFINITION in values:
value = values[DEFINITION]
text = "0" if value is None else str(value).strip("\"'() ")
if text not in ("0", "1"):
raise ValueError(DEFINITION + " override must be 0 or 1")
if text == "1" and not qualified:
raise ValueError(DEFINITION + "=1 requires only the repeater source role")
return {}
return {DEFINITION: 1} if qualified else {}
def install(build_env):
src_filter = build_env.get("SRC_FILTER")
if src_filter is None:
src_filter = build_env.GetProjectOption("build_src_filter", "")
definitions = role_policy(src_filter, build_env.get("BUILD_FLAGS", ()),
build_env.get("CPPDEFINES", ()))
definitions.update(companion_role_policy(src_filter, build_env.get("BUILD_FLAGS", ()),
build_env.get("CPPDEFINES", ())))
if definitions:
build_env.AppendUnique(CPPDEFINES=list(definitions.items()))
if "Import" in globals():
Import("env")
install(env)