mirror of
https://github.com/Colorado-Mesh/meshcore-bot-firmware.git
synced 2026-08-11 08:10:29 +00:00
Upstream MeshCore only added ${cmesh_bot_production.build_flags} to
Heltec V3 and RAK 4631 companion envs. Every other companion build
target (~129 envs across 64 boards) compiled without CMESH_BOT_ENABLED,
so the bot code was stripped at preprocessing and the firmware behaved
like stock MeshCore (no replies on #bot).
Caught when a tester reported the Heltec V4 build wouldn't respond to
commands. The fix isn't board-specific -- it applies to every variant
in the release matrix.
Adds scripts/enable-bot-on-companion-envs.py: scans
vendor/MeshCore/variants/*/platformio.ini, finds every
*_companion_radio_(usb|ble) env, injects ${cmesh_bot_production.build_flags}
into its build_flags block (idempotent). Hooks into apply-patches.sh
so every local / CI build picks it up.
Choosing a script over a vendor patch keeps us robust to upstream
adding new boards: we don't have to maintain a per-variant patch.
103 lines
3.7 KiB
Python
Executable File
103 lines
3.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Inject ${cmesh_bot_production.build_flags} into every
|
|
*_companion_radio_(usb|ble) env across vendor/MeshCore/variants/.
|
|
|
|
Run after scripts/apply-patches.sh. Idempotent: skips envs that already
|
|
include the flag.
|
|
|
|
Upstream MeshCore only includes cmesh_bot_production in Heltec V3 and
|
|
RAK 4631 variants. For our release matrix (133 companion envs) we want
|
|
the bot enabled everywhere, and we don't want to maintain a patch
|
|
that has to be kept in sync with every new upstream board.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1] / "vendor" / "MeshCore" / "variants"
|
|
ENV_HEADER = re.compile(r"^\[env:[A-Za-z0-9_-]+_companion_radio_(?:usb|ble)\]\s*$")
|
|
NEW_SECTION = re.compile(r"^\[")
|
|
INJECT_LINE = " ${cmesh_bot_production.build_flags}"
|
|
|
|
|
|
def process_file(path: Path) -> int:
|
|
lines = path.read_text().splitlines()
|
|
out: list[str] = []
|
|
i = 0
|
|
injected = 0
|
|
while i < len(lines):
|
|
line = lines[i]
|
|
if ENV_HEADER.match(line):
|
|
# Collect this env block until the next [section] header (or EOF).
|
|
j = i + 1
|
|
while j < len(lines) and not NEW_SECTION.match(lines[j]):
|
|
j += 1
|
|
block = lines[i:j]
|
|
|
|
if "${cmesh_bot_production.build_flags}" in "\n".join(block):
|
|
out.extend(block)
|
|
else:
|
|
# Find the last indented continuation line of the build_flags block
|
|
# so we can append the injection after it.
|
|
in_flags = False
|
|
last_flag_idx = -1
|
|
for k, ln in enumerate(block):
|
|
stripped = ln.lstrip()
|
|
if stripped.startswith("build_flags"):
|
|
in_flags = True
|
|
last_flag_idx = k
|
|
elif in_flags:
|
|
# A continuation line of build_flags must be indented
|
|
# with whitespace; comments and blanks don't count.
|
|
if (ln.startswith(" ") or ln.startswith("\t")) and not stripped.startswith(";"):
|
|
last_flag_idx = k
|
|
elif ln.startswith(" ") or ln.startswith("\t"):
|
|
# An indented comment - stays inside the block but doesn't
|
|
# change the insertion point.
|
|
pass
|
|
else:
|
|
# Hit a non-indented line (likely build_src_filter or lib_deps).
|
|
in_flags = False
|
|
if last_flag_idx >= 0:
|
|
block = block[: last_flag_idx + 1] + [INJECT_LINE] + block[last_flag_idx + 1 :]
|
|
injected += 1
|
|
out.extend(block)
|
|
i = j
|
|
continue
|
|
out.append(line)
|
|
i += 1
|
|
|
|
if injected > 0:
|
|
path.write_text("\n".join(out) + "\n")
|
|
return injected
|
|
|
|
|
|
def main() -> int:
|
|
if not ROOT.is_dir():
|
|
print(f"variants dir not found: {ROOT}", file=sys.stderr)
|
|
return 1
|
|
|
|
total = 0
|
|
files_touched = 0
|
|
for ini in sorted(ROOT.rglob("platformio.ini")):
|
|
n = process_file(ini)
|
|
if n:
|
|
print(f" + {ini.relative_to(ROOT.parent.parent.parent)}: injected into {n} env(s)")
|
|
files_touched += 1
|
|
total += n
|
|
|
|
if total == 0:
|
|
print("All companion_radio_(usb|ble) envs already include cmesh_bot_production.build_flags.")
|
|
else:
|
|
print(
|
|
f"Injected cmesh_bot_production.build_flags into {total} env(s) "
|
|
f"across {files_touched} variant file(s)."
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|