Consolidate duplicate Full infrastructure builds

This commit is contained in:
mikecarper committed 2026-09-10 19:33:54 -07:00
1 parent d6869b0af9
commit 2bc6847a1a
3 files changed
+217 -1

No files matched your search

+70 -1
View File
@@ -138,7 +138,7 @@ Options:
--firmware-version <version>: Firmware version to embed.
--radio-preset <name|number>: Override the USA Cascadia radio default. Stable names are usa-cascadia and target; legacy menu numbers remain accepted.
--profile <default|cascade>: Override runtime settings embedded in the firmware (not its feature set).
--build-profile <auto|standard|full>: Select feature/partition policy. Auto first builds complete LoRa-OTA-capable firmware. A measured size failure triggers the reduced recipe; internal-flash nRF52 repeaters also publish the reduced image for extra delta-staging headroom. Standard applies declared portable-image reductions immediately; full requires the expanded ESP32 recipe.
--build-profile <auto|standard|full>: Select feature/partition policy. Auto uses the combined Full MQTT/USB/WiFi recipe when it covers the plain infrastructure target; otherwise it first builds complete LoRa-OTA-capable firmware with a measured-size fallback. Internal-flash nRF52 repeaters also publish the reduced image for delta-staging headroom. Standard preserves portable images, including the 1.25 MiB slot; full requires the expanded ESP32 recipe.
--auto|--standard|--full: Short forms of --build-profile.
--skip-kiss|--include-kiss: Exclude (default) or include KISS modem targets in bulk builds.
--clean|--resume: Clean output or resume existing Option 3/FULL-only artifacts.
@@ -2340,6 +2340,57 @@ get_mqtt_disabled_target() {
echo "$candidate"
}
get_unified_full_infrastructure_target() {
local target=$1
local candidate
local base=${target%_}
[ "${PIO_ENV_PLATFORM_BY_NAME[$target]:-}" = "ESP32_PLATFORM" ] || return 1
case "${base,,}" in
*_repeater|*_room_server|*_repeater_observer_mqtt|*_room_server_observer_mqtt) ;;
*) return 1 ;;
esac
# These plain Full recipes retain more routing capacity than their MQTT
# siblings (T-Beam flood rules / room neighbors, TLora repeater neighbors).
# They are intentional alternatives, not duplicate Full artifacts.
case "${base,,}" in
tbeam_sx1262_repeater|tbeam_sx1276_repeater|\
tbeam_sx1262_room_server|tbeam_sx1276_room_server|\
lilygo_tlora_v2_1_1_6_repeater) return 1 ;;
esac
# Some exact hardware recipes have a trailing underscore on either side.
# Require the same board as well as the same role/hardware name; never fold
# a display, radio, storage, Ethernet, or serial-bridge variant into this.
for candidate in "$target" "${base}_observer_mqtt" "${base}_observer_mqtt_"; do
if is_mqtt_bridge_target "$candidate" \
&& supports_esp32_full_build "$candidate" \
&& [ -n "${PIO_ENV_BOARD_BY_NAME[$target]:-}" ] \
&& [ "${PIO_ENV_BOARD_BY_NAME[$target]}" = "${PIO_ENV_BOARD_BY_NAME[$candidate]:-}" ]; then
printf '%s\n' "$candidate"
return 0
fi
done
return 1
}
configure_unified_full_infrastructure_output() {
[ "$ESP32_FULL_BUILD" = "1" ] && is_mqtt_bridge_target "$1" || return 0
case "${1,,}" in
*_repeater_observer_mqtt|*_repeater_observer_mqtt_|\
*_room_server_observer_mqtt|*_room_server_observer_mqtt_) ;;
*) return 0 ;;
esac
# A direct/auto observer build and a matrix build must produce the same
# runtime-selectable artifact, not MQTT-only and USB+MQTT Full twins.
MESHDEBUG_OVERRIDE="off"
PACKET_LOGGING_OVERRIDE="on"
MQTT_BRIDGE_OVERRIDE="on"
MQTT_DEBUG_OVERRIDE="off"
FIRMWARE_FILENAME_INFIX="full-usb-wifi"
}
normalize_resolved_targets_for_mqtt() {
local command=$1
local target
@@ -4013,6 +4064,10 @@ build_firmware() {
local inherited_firmware_filename_infix=$FIRMWARE_FILENAME_INFIX
local ESP32_FULL_BUILD=$inherited_esp32_full_build
local FIRMWARE_FILENAME_INFIX=$inherited_firmware_filename_infix
local MESHDEBUG_OVERRIDE=$MESHDEBUG_OVERRIDE
local PACKET_LOGGING_OVERRIDE=$PACKET_LOGGING_OVERRIDE
local MQTT_BRIDGE_OVERRIDE=$MQTT_BRIDGE_OVERRIDE
local MQTT_DEBUG_OVERRIDE=$MQTT_DEBUG_OVERRIDE
env_platform=$(get_platform_for_env "$env_name")
if ! is_supported_platform "$env_platform"; then
@@ -4046,6 +4101,7 @@ build_firmware() {
|| is_companion_radio_full_target "$env_name"; then
BUILD_PROFILE_FOR_TARGET="full"
fi
configure_unified_full_infrastructure_output "$env_name"
echo "Effective feature profile for ${env_name}: ${BUILD_PROFILE_FOR_TARGET}"
commit_hash=$(git rev-parse --short HEAD)
@@ -4874,6 +4930,7 @@ configure_effective_build_profile() {
local command_name=$1
local target=""
local reduced_target=""
local unified_target=""
if [ "${#RESOLVED_BUILD_TARGETS[@]}" -eq 1 ]; then
target=${RESOLVED_BUILD_TARGETS[0]}
@@ -4908,6 +4965,12 @@ configure_effective_build_profile() {
&& [ "${#RESOLVED_BUILD_TARGETS[@]}" -eq 1 ]; then
if is_companion_radio_full_target "$target"; then
BUILD_PROFILE_EFFECTIVE="full"
elif unified_target=$(get_unified_full_infrastructure_target "$target"); then
BUILD_PROFILE_EFFECTIVE="full"
SINGLE_TARGET_FULL_BUILD=1
RESOLVED_BUILD_TARGETS=("$unified_target")
echo "Using ${unified_target} as the combined Full image for ${target}; logging/MQTT are runtime settings."
echo "Use --build-profile standard for the original portable partition/OTA target contract."
elif supports_esp32_full_build "$target"; then
BUILD_PROFILE_EFFECTIVE="full"
AUTO_PREFER_FULL_BUILD=1
@@ -5309,6 +5372,12 @@ run_full_esp32_profile() {
for target in "${targets[@]}"; do
full_profile_target=$(get_esp32_full_profile_target "$target")
# Use the same exact-board choice as single-target auto builds, including
# historical trailing-underscore recipes such as Heltec T190.
mqtt_target=$(get_unified_full_infrastructure_target "$full_profile_target") || mqtt_target=""
if [ -n "$mqtt_target" ]; then
full_profile_target=$mqtt_target
fi
full_target=""
if [ "$profile_mode" = "fallback" ]; then
# A matching MQTT environment is emitted once by the unified profile;
+16
View File
@@ -43,6 +43,22 @@ host-mOTA controls for Full Companion, and the
advanced flood-rule engine for Full room servers. Resume mode will not accept
an old or failed artifact without a verified sidecar.
For a single ESP32 repeater or room-server target, `auto` selects its matching
combined Full MQTT/USB/WiFi image when that image covers the plain Full recipe.
The direct observer and Full-matrix paths use the same `full-usb-wifi-ota`
artifact and runtime output controls. Plain Full T-Beam SX1262/SX1276 profiles
and the TLora V2 repeater remain alternatives because their MQTT siblings have
lower routing-table capacities.
Standard and reduced OTA images, including images that fit the 1.25 MiB
portable application slot, remain available and remain in the standard matrix
pass. Select `--build-profile standard` to retain the original target and
partition contract. Moving from a plain target to its MQTT sibling changes the
LoRa OTA target identity; existing nodes need an appropriate wired migration.
The default `cascade` settings profile enables device and LoRa RX power saving;
saved preferences take precedence, and active USB/network services can prevent
device sleep. `--profile default` instead uses the upstream power-saving defaults.
## Role comes first
| Role | Text administration CLI |
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
source build.sh
fail() { echo "test_full_infrastructure_selection: $*" >&2; exit 1; }
# Resolve real board inheritance, but never compile or flash firmware.
init_project_context >/dev/null
assert_auto_unified() (
local plain=$1 expected=$2
BUILD_PROFILE_OVERRIDE=auto
BUILD_PROFILE_EXPLICIT=0
SINGLE_TARGET_FULL_BUILD=0
RESOLVED_BUILD_TARGETS=("$plain")
configure_effective_build_profile build-firmware >/dev/null
[ "${RESOLVED_BUILD_TARGETS[*]}" = "$expected" ] || fail "$plain selected the wrong target"
[ "$SINGLE_TARGET_FULL_BUILD" = 1 ] || fail "$plain bypassed the unified recipe"
[ "$AUTO_PREFER_FULL_BUILD" = 0 ] || fail "$plain still schedules a plain Full artifact"
local -a built=()
run_logged_build_targets() {
[ "$FIRMWARE_FILENAME_INFIX" = full-usb-wifi ] || fail "wrong artifact name"
[ "$ESP32_FULL_BUILD" = 1 ] || fail "lost expanded partitions"
[ "$PACKET_LOGGING_OVERRIDE" = on ] || fail "lost USB packet logging"
[ "$MQTT_BRIDGE_OVERRIDE" = on ] || fail "lost MQTT"
[ "$MESHDEBUG_OVERRIDE" = off ] || fail "enabled verbose debug"
built+=("$@")
}
run_command build-firmware >/dev/null
[ "${built[*]}" = "$expected" ] || fail "auto emitted duplicate Full artifacts"
built=()
run_full_esp32_build_targets all "$plain" "$expected" >/dev/null
[ "${built[*]}" = "$expected" ] || fail "matrix emitted duplicate Full artifacts"
)
assert_auto_unified heltec_v4_r8_repeater heltec_v4_r8_repeater_observer_mqtt
assert_auto_unified heltec_v4_r8_room_server heltec_v4_r8_room_server_observer_mqtt
assert_auto_unified heltec_v4_r8_tft_repeater heltec_v4_r8_tft_repeater_observer_mqtt
assert_auto_unified Heltec_T190_repeater_ Heltec_T190_repeater_observer_mqtt
assert_auto_unified LilyGo_TLora_V2_1_1_6_room_server LilyGo_TLora_V2_1_1_6_room_server_observer_mqtt_
assert_auto_unified heltec_v4_r8_repeater_observer_mqtt heltec_v4_r8_repeater_observer_mqtt
# Portable images and exact reduced OTA identities must not be consolidated.
for target in heltec_v4_r8_repeater heltec_v4_r8_room_server \
heltec_v4_r8_repeater_lora_ota_no_external_sensors; do
(
BUILD_PROFILE_OVERRIDE=standard
BUILD_PROFILE_EXPLICIT=1
SINGLE_TARGET_FULL_BUILD=0
RESOLVED_BUILD_TARGETS=("$target")
configure_effective_build_profile build-firmware >/dev/null
[ "${RESOLVED_BUILD_TARGETS[*]}" = "$target" ] || fail "lost portable target $target"
[ "$BUILD_PROFILE_EFFECTIVE" = standard ] || fail "expanded portable image $target"
[ "$SINGLE_TARGET_FULL_BUILD" = 0 ] || fail "portable image entered Full pipeline"
)
done
for target in Tbeam_SX1262_repeater Tbeam_SX1276_repeater \
Tbeam_SX1262_room_server Tbeam_SX1276_room_server \
LilyGo_TLora_V2_1_1_6_repeater \
heltec_v4_r8_repeater_lora_ota_no_external_sensors \
RAK_4631_repeater_bridge_rs232_serial1_lora_ota_no_external_sensors; do
if get_unified_full_infrastructure_target "$target" >/dev/null; then
fail "consolidated a distinct capacity/OTA contract: $target"
fi
done
(
PIO_ENV_BOARD_BY_NAME[heltec_v4_r8_repeater_observer_mqtt]=different_board
if get_unified_full_infrastructure_target heltec_v4_r8_repeater >/dev/null; then
fail "accepted a different physical board"
fi
)
# Direct observer promotion must use the matrix's exact output recipe even if
# interactive flags previously requested MQTT without USB logging. Stop at the
# existing-artifact check to exercise the real build entry point without pio run.
(
ESP32_FULL_BUILD=0
BUILD_PROFILE_EFFECTIVE=standard
BUILD_PROFILE_OVERRIDE=auto
BUILD_PROFILE_EXPLICIT=0
FIRMWARE_VERSION=vtest
RESUME_BUILD_OUTPUT=1
FIRMWARE_FILENAME_INFIX=""
MESHDEBUG_OVERRIDE=on
PACKET_LOGGING_OVERRIDE=off
MQTT_BRIDGE_OVERRIDE=off
MQTT_DEBUG_OVERRIDE=on
observed_filename=""
observed_output=""
build_artifacts_exist() {
observed_filename=$2
observed_output="$PACKET_LOGGING_OVERRIDE/$MQTT_BRIDGE_OVERRIDE/$MESHDEBUG_OVERRIDE/$MQTT_DEBUG_OVERRIDE"
return 0
}
build_firmware heltec_v4_r8_repeater_observer_mqtt >/dev/null
[[ "$observed_filename" == heltec_v4_r8_repeater_observer_mqtt-full-usb-wifi-ota-vtest-* ]] \
|| fail "direct observer kept a duplicate name"
[ "$observed_output" = on/on/off/off ] || fail "direct observer differs from unified recipe"
[ "$PACKET_LOGGING_OVERRIDE/$MQTT_BRIDGE_OVERRIDE/$MESHDEBUG_OVERRIDE/$MQTT_DEBUG_OVERRIDE" = off/off/on/on ] \
|| fail "observer output settings leaked into subsequent builds"
)
(
standard_built=""
full_built=""
REQUIRE_OTA_UPDATES=0
run_logged_build_targets() {
if [ "$ESP32_FULL_BUILD" = 0 ]; then standard_built="$*"; else full_built="$*"; fi
}
run_logging_matrix_build_targets heltec_v4_r8_repeater \
heltec_v4_r8_repeater_lora_ota_no_external_sensors \
heltec_v4_r8_repeater_observer_mqtt >/dev/null
[ "$standard_built" = 'heltec_v4_r8_repeater heltec_v4_r8_repeater_lora_ota_no_external_sensors' ] \
|| fail "matrix removed a portable build"
[ "$full_built" = heltec_v4_r8_repeater_observer_mqtt ] || fail "matrix duplicated Full"
[ "$ESP32_LORA_OTA_APP_LIMIT" = 1310720 ] || fail "changed the 1.25 MiB portable limit"
)
# The default build settings retain power saving; this does not overwrite
# preferences already stored on a device.
[ "$FIRMWARE_PROFILE_OVERRIDE" = cascade ] || fail "default profile changed"
PLATFORMIO_BUILD_FLAGS=""
apply_firmware_profile_overrides
[[ "$PLATFORMIO_BUILD_FLAGS" == *-DDEFAULT_POWERSAVING_ENABLED=1* ]] || fail "device power saving disabled"
[[ "$PLATFORMIO_BUILD_FLAGS" == *-DDEFAULT_RXPS_ENABLED=1* ]] || fail "RX power saving disabled"
echo "test_full_infrastructure_selection: OK"