From ba00097cc44b9c50d0c544ebc7d56c2616ee4bcc Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 02:39:58 -0700 Subject: [PATCH 1/8] build: use soldr PEP517 backend for local installs --- Cargo.toml | 2 +- MANIFEST.in | 1 - build_backend.py | 91 ---------------------------------- docs/getting-started/README.md | 4 +- pyproject.toml | 19 ++++--- setup.py | 22 ++++++-- 6 files changed, 31 insertions(+), 108 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 build_backend.py diff --git a/Cargo.toml b/Cargo.toml index d4306498..0399653b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -154,7 +154,7 @@ owo-colors = "4" running-process = { version = "4.5.7", default-features = false, features = ["client-async"] } [profile.dev] -debug = 0 +debug = "line-tables-only" # Cargo's dev defaults: opt-level = 0 for first-party (fast compile + # fast link), incremental = true (cargo + linker keep state across # builds), codegen-units = 256 (parallel compile units). We accept diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 553f6922..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include build_backend.py diff --git a/build_backend.py b/build_backend.py deleted file mode 100644 index ebbf0662..00000000 --- a/build_backend.py +++ /dev/null @@ -1,91 +0,0 @@ -"""PEP 517 adapter for fbuild's setuptools backend. - -Pip cannot append arbitrary Cargo arguments to a PEP 517 build. It can, -however, pass backend configuration through ``--config-settings``. Translate -the fbuild-specific profile setting into the environment variable consumed by -``setup.py`` and delegate all other behavior to setuptools. -""" - -from __future__ import annotations - -import os -from contextlib import contextmanager -from typing import Iterator - -from setuptools import build_meta as _setuptools - - -def _setting(config_settings: dict[str, object] | None, name: str) -> str | None: - if not config_settings or name not in config_settings: - return None - value = config_settings[name] - if isinstance(value, list): - value = value[-1] if value else "" - return str(value).strip().lower() - - -@contextmanager -def _profile_environment(config_settings: dict[str, object] | None) -> Iterator[None]: - """Apply the requested fbuild profile only while setuptools builds.""" - profile = _setting(config_settings, "fbuild-profile") - release = _setting(config_settings, "fbuild-release") - if profile is not None and profile not in {"dev", "debug", "release"}: - raise ValueError("fbuild-profile must be 'dev'/'debug' or 'release'") - if release is not None and release not in {"0", "1", "false", "true", "no", "yes"}: - raise ValueError("fbuild-release must be a boolean value") - - requested_release = ( - profile == "release" - if profile is not None - else release in {"1", "true", "yes"} - if release is not None - else None - ) - if requested_release is None: - yield - return - - previous = os.environ.get("FBUILD_BUILD_RELEASE") - os.environ["FBUILD_BUILD_RELEASE"] = "1" if requested_release else "0" - try: - yield - finally: - if previous is None: - os.environ.pop("FBUILD_BUILD_RELEASE", None) - else: - os.environ["FBUILD_BUILD_RELEASE"] = previous - - -def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): - with _profile_environment(config_settings): - return _setuptools.build_wheel(wheel_directory, config_settings, metadata_directory) - - -def build_editable(wheel_directory, config_settings=None, metadata_directory=None): - with _profile_environment(config_settings): - return _setuptools.build_editable(wheel_directory, config_settings, metadata_directory) - - -def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): - with _profile_environment(config_settings): - return _setuptools.prepare_metadata_for_build_wheel(metadata_directory, config_settings) - - -def get_requires_for_build_wheel(config_settings=None): - with _profile_environment(config_settings): - return _setuptools.get_requires_for_build_wheel(config_settings) - - -def build_sdist(sdist_directory, config_settings=None): - with _profile_environment(config_settings): - return _setuptools.build_sdist(sdist_directory, config_settings) - - -def get_requires_for_build_sdist(config_settings=None): - with _profile_environment(config_settings): - return _setuptools.get_requires_for_build_sdist(config_settings) - - -def prepare_metadata_for_build_editable(metadata_directory, config_settings=None): - with _profile_environment(config_settings): - return _setuptools.prepare_metadata_for_build_editable(metadata_directory, config_settings) diff --git a/docs/getting-started/README.md b/docs/getting-started/README.md index 1d6ddfee..05169f5a 100644 --- a/docs/getting-started/README.md +++ b/docs/getting-started/README.md @@ -24,11 +24,11 @@ keeps local rebuilds quick. To explicitly build an optimized Rust wheel, pass the PEP 517 backend setting: ```bash -pip install . --config-settings fbuild-profile=release +pip install . --config-settings profile=release ``` `pip install . -- --release` is not supported: pip does not forward arbitrary -arguments after `--` to a PEP 517 backend. The `fbuild-profile` setting (or +arguments after `--` to a PEP 517 backend. The `profile=release` setting (or `FBUILD_BUILD_RELEASE=1`) is the supported release override. ## First Project diff --git a/pyproject.toml b/pyproject.toml index db783dbf..09d431a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,15 +55,18 @@ cache-keys = [ ] [build-system] -requires = ["setuptools>=64"] -build-backend = "build_backend" -backend-path = ["."] +# 0.8.19 is the first soldr release containing delegated PEP 517 hooks. +requires = ["soldr>=0.8.19", "setuptools>=64"] +build-backend = "soldr" -# Local/source installs use Cargo's dev profile (no LTO) by default. To -# request an optimized Rust wheel through pip, use: -# pip install . --config-settings fbuild-profile=release -# A literal `pip install . -- --release` cannot be forwarded through the PEP -# 517 interface; `--config-settings` is the standard backend override. +# soldr owns the PEP 517 environment/profile/cache policy, while setuptools +# retains fbuild's native CLI/daemon/PyO3 staging implementation in setup.py. +[tool.soldr.pep517] +delegate-backend = "setuptools.build_meta" + +# Local/source installs use soldr's fast dev profile by default. To request a +# release-profile source build through PEP 517, use: +# pip install . --config-settings profile=release [tool.setuptools] packages = ["fbuild", "fbuild.api"] diff --git a/setup.py b/setup.py index 0162670d..cf16042d 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ """Local source-install build driver for fbuild. `pip install ~/dev/fbuild` (or any `pip install .` from the repo root) goes -through this file because `pyproject.toml` declares the setuptools build -backend. The plain backend would ship only the `python/fbuild` Python +through this file because soldr delegates the PEP 517 hooks to setuptools. +The plain backend would ship only the `python/fbuild` Python package — no working `fbuild` command — because the actual CLI is a Rust crate (`fbuild-cli`) that lives in the cargo workspace under `crates/`. @@ -267,10 +267,22 @@ def _use_release_profile() -> bool: 3 via `[profile.dev.package."*"]`, only our own crates compile unoptimized). Set `FBUILD_BUILD_RELEASE=1` to opt into a release build when you actually want a fast binary (CI, packaging, perf - tests). PEP 517 callers can use `--config-settings fbuild-profile=release`; - `build_backend.py` translates that setting to this environment variable. + tests). PEP 517 callers can use `--config-settings profile=release`; + soldr translates that setting to the delegated build environment. """ - return os.environ.get("FBUILD_BUILD_RELEASE", "").lower() in ("1", "true", "yes") + explicit_release = os.environ.get("FBUILD_BUILD_RELEASE") + if explicit_release is not None: + return explicit_release.lower() in ("1", "true", "yes") + + soldr_profile = os.environ.get("SOLDR_PEP517_PROFILE", "").strip().lower() + if soldr_profile in ("", "dev", "debug"): + return False + if soldr_profile == "release": + return True + raise ValueError( + "fbuild source installs support soldr profiles 'dev'/'debug' and 'release'; " + f"got {soldr_profile!r}" + ) def _profile_subdir() -> str: From 99e4dfe5b50d6863b06ecf1baca46f8b0fcefc59 Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 03:28:07 -0700 Subject: [PATCH 2/8] ci: provide soldr to no-isolation builds --- pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 09d431a7..60f7ef3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,9 @@ fbuild-dev-tools = { path = "ci/dev-tools", editable = true } [tool.uv] no-build-isolation-package = ["fbuild"] default-groups = ["dev"] +# `no-build-isolation-package` uses the project environment for fbuild's +# setup.py. Inject soldr there as well as declaring it in build-system.requires +# so `uv sync` has the delegated backend available before rebuilding fbuild. # Tell uv to re-sync the editable install when these change. Without # this, `uv run` after a .rs edit silently uses a stale _native.pyd # because uv's default cache-keys only watch pyproject.toml. @@ -54,6 +57,9 @@ cache-keys = [ { file = "crates/**/Cargo.toml" }, ] +[tool.uv.extra-build-dependencies] +fbuild = ["setuptools>=64", "soldr>=0.8.19"] + [build-system] # 0.8.19 is the first soldr release containing delegated PEP 517 hooks. requires = ["soldr>=0.8.19", "setuptools>=64"] From 95fa413cdcea16242f505178802f6ecad7f9313a Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 04:00:26 -0700 Subject: [PATCH 3/8] ci: seed soldr for local no-isolation builds --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 60f7ef3e..95984966 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,9 +23,9 @@ dependencies = [] # setuptools is in dev (not project deps) because fbuild uses # no-build-isolation: the build runs in the project venv, so setuptools # must already be installed when uv tries to (re)build the wheel. -# default-groups below makes uv install dev (and hence setuptools) +# default-groups below makes uv install dev (and hence setuptools and soldr) # before attempting to build, breaking the chicken-and-egg. -dev = ["fbuild-dev-tools", "setuptools>=64"] +dev = ["fbuild-dev-tools", "setuptools>=64", "soldr>=0.8.19"] [tool.uv.sources] fbuild-dev-tools = { path = "ci/dev-tools", editable = true } From 03520dec72cc47dbf5948f37957a60391f510a24 Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 04:16:29 -0700 Subject: [PATCH 4/8] style: format current port scan changes --- crates/fbuild-cli/src/cli/port_scan.rs | 5 ++- crates/fbuild-serial/src/ports.rs | 43 +++++++++++++------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/crates/fbuild-cli/src/cli/port_scan.rs b/crates/fbuild-cli/src/cli/port_scan.rs index 8d3e0d07..41527d3a 100644 --- a/crates/fbuild-cli/src/cli/port_scan.rs +++ b/crates/fbuild-cli/src/cli/port_scan.rs @@ -57,7 +57,10 @@ fn run_scan(offline: bool) -> Result<()> { if !problem_devices.is_empty() { // This is actionable final command output. Keep it visible under the // default tracing filter instead of requiring users to set RUST_LOG. - output::diagnostic(format!("warning: {}", format_usb_problem_warning(&problem_devices))); + output::diagnostic(format!( + "warning: {}", + format_usb_problem_warning(&problem_devices) + )); } Ok(()) } diff --git a/crates/fbuild-serial/src/ports.rs b/crates/fbuild-serial/src/ports.rs index 40315119..b96022c5 100644 --- a/crates/fbuild-serial/src/ports.rs +++ b/crates/fbuild-serial/src/ports.rs @@ -78,9 +78,9 @@ mod imp { use serialport::{SerialPortInfo, SerialPortType, UsbPortInfo}; use windows_sys::Win32::Devices::DeviceAndDriverInstallation::{ CM_Get_DevNode_Status, CM_Get_Device_IDW, CM_Get_Parent, CR_SUCCESS, DICS_FLAG_GLOBAL, - DIGCF_PRESENT, DIREG_DEV, GUID_DEVCLASS_USB, HDEVINFO, MAX_DEVICE_ID_LEN, - SP_DEVINFO_DATA, SPDRP_FRIENDLYNAME, SPDRP_HARDWAREID, SPDRP_LOCATION_INFORMATION, - SPDRP_MFG, SetupDiClassGuidsFromNameW, SetupDiDestroyDeviceInfoList, SetupDiEnumDeviceInfo, + DIGCF_PRESENT, DIREG_DEV, GUID_DEVCLASS_USB, HDEVINFO, MAX_DEVICE_ID_LEN, SP_DEVINFO_DATA, + SPDRP_FRIENDLYNAME, SPDRP_HARDWAREID, SPDRP_LOCATION_INFORMATION, SPDRP_MFG, + SetupDiClassGuidsFromNameW, SetupDiDestroyDeviceInfoList, SetupDiEnumDeviceInfo, SetupDiGetClassDevsW, SetupDiGetDeviceInstanceIdW, SetupDiGetDeviceRegistryPropertyW, SetupDiOpenDevRegKey, }; @@ -440,13 +440,15 @@ mod imp { break; } let mut buffer = [0u16; MAX_DEVICE_ID_LEN as usize]; - let result = unsafe { - CM_Get_Device_IDW(parent, buffer.as_mut_ptr(), buffer.len() as u32, 0) - }; + let result = + unsafe { CM_Get_Device_IDW(parent, buffer.as_mut_ptr(), buffer.len() as u32, 0) }; if result != CR_SUCCESS { break; } - let length = buffer.iter().position(|&unit| unit == 0).unwrap_or(buffer.len()); + let length = buffer + .iter() + .position(|&unit| unit == 0) + .unwrap_or(buffer.len()); ids.push(String::from_utf16_lossy(&buffer[..length])); current = parent; } @@ -455,9 +457,9 @@ mod imp { fn classify_usb_ancestry(devinst: u32) -> Option { let ancestors = ancestor_ids(devinst); - let root_index = ancestors.iter().position(|id| { - id.to_ascii_uppercase().starts_with("USB\\ROOT_HUB") - })?; + let root_index = ancestors + .iter() + .position(|id| id.to_ascii_uppercase().starts_with("USB\\ROOT_HUB"))?; Some(ancestors[..root_index].iter().any(|id| { let upper = id.to_ascii_uppercase(); upper.starts_with("USB\\VID_") && upper.contains("&PID_") @@ -465,14 +467,8 @@ mod imp { } pub(super) fn present_usb_problem_devices() -> Vec { - let hdi = unsafe { - SetupDiGetClassDevsW( - &GUID_DEVCLASS_USB, - std::ptr::null(), - 0, - DIGCF_PRESENT, - ) - }; + let hdi = + unsafe { SetupDiGetClassDevsW(&GUID_DEVCLASS_USB, std::ptr::null(), 0, DIGCF_PRESENT) }; if hdi == INVALID_HANDLE_VALUE { return Vec::new(); } @@ -535,7 +531,10 @@ mod imp { if ok == FALSE { return None; } - let length = buffer.iter().position(|&unit| unit == 0).unwrap_or(buffer.len()); + let length = buffer + .iter() + .position(|&unit| unit == 0) + .unwrap_or(buffer.len()); Some(String::from_utf16_lossy(&buffer[..length])) } @@ -560,7 +559,10 @@ mod imp { if ok == FALSE || value_type != REG_SZ { return None; } - let length = buffer.iter().position(|&unit| unit == 0).unwrap_or(buffer.len()); + let length = buffer + .iter() + .position(|&unit| unit == 0) + .unwrap_or(buffer.len()); let value = String::from_utf16_lossy(&buffer[..length]); (!value.is_empty()).then_some(value) } @@ -750,6 +752,5 @@ mod imp { assert_eq!(info.interface, None); assert_eq!(info.serial_number.as_deref(), Some("B4:3A:45:B0:08:24")); } - } } From f17d035da41c4ee5537e59ef12f62d2d905a72e0 Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 04:32:47 -0700 Subject: [PATCH 5/8] fix: initialize clean_all in AVR test helper --- crates/fbuild-build/tests/avr_build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/fbuild-build/tests/avr_build.rs b/crates/fbuild-build/tests/avr_build.rs index 4c9ddf9e..7839bc7a 100644 --- a/crates/fbuild-build/tests/avr_build.rs +++ b/crates/fbuild-build/tests/avr_build.rs @@ -125,6 +125,7 @@ async fn build_uno_minimal() { src_dir: None, pio_env: Default::default(), extra_build_flags: Vec::new(), + clean_all: false, watch_set_cache: None, bloat_analysis: false, }; From 412f89e5bb5a320c5acd995305e6ef4e523bba44 Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 04:35:48 -0700 Subject: [PATCH 6/8] fix: place AVR clean_all default in helper --- crates/fbuild-build/tests/avr_build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fbuild-build/tests/avr_build.rs b/crates/fbuild-build/tests/avr_build.rs index 7839bc7a..c2bf4352 100644 --- a/crates/fbuild-build/tests/avr_build.rs +++ b/crates/fbuild-build/tests/avr_build.rs @@ -125,7 +125,6 @@ async fn build_uno_minimal() { src_dir: None, pio_env: Default::default(), extra_build_flags: Vec::new(), - clean_all: false, watch_set_cache: None, bloat_analysis: false, }; @@ -366,6 +365,7 @@ fn uno_build_params(project_dir: &Path, build_dir: PathBuf, clean: bool) -> Buil project_dir: project_dir.to_path_buf(), env_name: "uno".to_string(), clean, + clean_all: false, profile: BuildProfile::Release, build_dir, verbose: false, From f0508fa00076393360c7e97020ecccbbdb14e945 Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 06:18:50 -0700 Subject: [PATCH 7/8] chore: format current-main Rust files --- .../fbuild-build-esp/src/esp32/orchestrator/build.rs | 5 ++++- .../src/esp32/orchestrator/framework_library_cache.rs | 5 ++++- .../src/esp32/orchestrator/framework_libs.rs | 10 ++++++++-- crates/fbuild-build-esp/src/esp32/orchestrator/mod.rs | 2 +- crates/fbuild-cli/src/cli/dispatch.rs | 8 +++++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/crates/fbuild-build-esp/src/esp32/orchestrator/build.rs b/crates/fbuild-build-esp/src/esp32/orchestrator/build.rs index 0ec7b530..1f0f92bc 100644 --- a/crates/fbuild-build-esp/src/esp32/orchestrator/build.rs +++ b/crates/fbuild-build-esp/src/esp32/orchestrator/build.rs @@ -614,7 +614,10 @@ impl BuildOrchestrator for Esp32Orchestrator { if params.clean_all { let _g = perf.phase("core-cache-remove"); match std::fs::remove_dir_all(core_cache.path()) { - Ok(()) => tracing::info!("removed framework core cache {}", core_cache.path().display()), + Ok(()) => tracing::info!( + "removed framework core cache {}", + core_cache.path().display() + ), Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} Err(error) => tracing::warn!( "failed to remove framework core cache {}: {}", diff --git a/crates/fbuild-build-esp/src/esp32/orchestrator/framework_library_cache.rs b/crates/fbuild-build-esp/src/esp32/orchestrator/framework_library_cache.rs index 6fad8a8d..667bb11e 100644 --- a/crates/fbuild-build-esp/src/esp32/orchestrator/framework_library_cache.rs +++ b/crates/fbuild-build-esp/src/esp32/orchestrator/framework_library_cache.rs @@ -254,7 +254,10 @@ mod tests { let hydrated = tmp.path().join("hydrated"); assert_eq!(cache.hydrate(&hydrated).unwrap(), 1); - assert_eq!(std::fs::read(hydrated.join("libwifi.a")).unwrap(), b"archive"); + assert_eq!( + std::fs::read(hydrated.join("libwifi.a")).unwrap(), + b"archive" + ); assert!(cache.has_failed("matter")); cache.remove().unwrap(); assert!(!cache.has_failed("matter")); diff --git a/crates/fbuild-build-esp/src/esp32/orchestrator/framework_libs.rs b/crates/fbuild-build-esp/src/esp32/orchestrator/framework_libs.rs index 60fb0f41..f77aa452 100644 --- a/crates/fbuild-build-esp/src/esp32/orchestrator/framework_libs.rs +++ b/crates/fbuild-build-esp/src/esp32/orchestrator/framework_libs.rs @@ -105,7 +105,9 @@ pub(super) async fn compile_framework_builtin_libs( if params.clean_all { match framework_cache.remove() { Ok(()) => tracing::info!("removed ESP32 framework library cache"), - Err(error) => tracing::warn!("failed to remove ESP32 framework library cache: {}", error), + Err(error) => { + tracing::warn!("failed to remove ESP32 framework library cache: {}", error) + } } } match framework_cache.hydrate(&fw_libs_build_dir) { @@ -260,7 +262,11 @@ pub(super) async fn compile_framework_builtin_libs( tracing::debug!("framework library {} failed to compile: {}", lib_name, e); record_failed_framework_lib(&failure_marker, &fw_signature, &e.to_string()); if let Err(error) = framework_cache.record_failure(&lib_name) { - tracing::warn!("failed to cache framework library failure {}: {}", lib_name, error); + tracing::warn!( + "failed to cache framework library failure {}: {}", + lib_name, + error + ); } } } diff --git a/crates/fbuild-build-esp/src/esp32/orchestrator/mod.rs b/crates/fbuild-build-esp/src/esp32/orchestrator/mod.rs index bd190fbe..f9d2a78a 100644 --- a/crates/fbuild-build-esp/src/esp32/orchestrator/mod.rs +++ b/crates/fbuild-build-esp/src/esp32/orchestrator/mod.rs @@ -28,8 +28,8 @@ mod cdc; mod embed; mod embed_stage; mod fingerprint; -mod framework_libs; mod framework_library_cache; +mod framework_libs; mod helpers; mod local_libs; mod packages; diff --git a/crates/fbuild-cli/src/cli/dispatch.rs b/crates/fbuild-cli/src/cli/dispatch.rs index 1d448485..2c207e37 100644 --- a/crates/fbuild-cli/src/cli/dispatch.rs +++ b/crates/fbuild-cli/src/cli/dispatch.rs @@ -193,7 +193,13 @@ pub async fn async_main() { }) => { let project_dir = resolve_project_dir(project_dir, &top_level_project_dir); if platformio { - pio_build(&project_dir, environment.as_deref(), clean || clean_all, verbose).await + pio_build( + &project_dir, + environment.as_deref(), + clean || clean_all, + verbose, + ) + .await } else { run_build( project_dir, From 7bb537d8e5d8f27b303127ec0172a6d33a3a3629 Mon Sep 17 00:00:00 2001 From: zackees Date: Thu, 16 Jul 2026 07:24:25 -0700 Subject: [PATCH 8/8] chore: format rp2040 deployment code --- crates/fbuild-deploy/src/rp2040.rs | 56 +++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/crates/fbuild-deploy/src/rp2040.rs b/crates/fbuild-deploy/src/rp2040.rs index 655c2149..8b107f8f 100644 --- a/crates/fbuild-deploy/src/rp2040.rs +++ b/crates/fbuild-deploy/src/rp2040.rs @@ -81,8 +81,7 @@ fn timeout_from_env(var_name: &str, default: Duration) -> Duration { } fn rp2040_post_deploy_timeout() -> Duration { - let timing = fbuild_serial::boards::BoardFamily::NativeUsbCdcReset1200Bps - .handoff_timing(); + let timing = fbuild_serial::boards::BoardFamily::NativeUsbCdcReset1200Bps.handoff_timing(); timeout_from_env( POST_DEPLOY_TIMEOUT_ENV, Duration::from_millis(u64::from(timing.application_cdc_timeout_ms)), @@ -1127,15 +1126,15 @@ fn resolve_post_flash_cdc( Err(CdcWaitError::Timeout(diagnostics)) if flash_confirmed => { tracing::warn!(diagnostics = %diagnostics.diagnostics(), "RP2040 runtime CDC did not return before the confirmed-flash deadline"); Ok(PostFlashCdc::Unconfirmed(format!( - "the firmware was flashed and accepted, but the runtime CDC port did not reappear within {}s; first-plug driver installation can exceed this window — the board is likely healthy (extend the window with {POST_DEPLOY_TIMEOUT_ENV})", - window.as_secs() + "the firmware was flashed and accepted, but the runtime CDC port did not reappear within {}s; first-plug driver installation can exceed this window — the board is likely healthy (extend the window with {POST_DEPLOY_TIMEOUT_ENV})", + window.as_secs() ))) } Err(CdcWaitError::Timeout(diagnostics)) => { tracing::warn!(diagnostics = %diagnostics.diagnostics(), "RP2040 runtime CDC did not return before the unconfirmed-flash deadline"); Err(FbuildError::DeployFailed(format!( - "RP2040 firmware was transferred, but no catalogue-identified runtime CDC port appeared within {}s; verify that the firmware enables USB serial and that FastLED/boards USB data is current (extend the window with {POST_DEPLOY_TIMEOUT_ENV})", - window.as_secs() + "RP2040 firmware was transferred, but no catalogue-identified runtime CDC port appeared within {}s; verify that the firmware enables USB serial and that FastLED/boards USB data is current (extend the window with {POST_DEPLOY_TIMEOUT_ENV})", + window.as_secs() ))) } } @@ -2069,18 +2068,17 @@ mod tests { #[test] fn cdc_timeout_after_confirmed_flash_downgrades_to_unconfirmed_success() { - let outcome = - resolve_post_flash_cdc( - true, - Err(CdcWaitError::Timeout(CdcWaitTimeout { - elapsed: Duration::from_secs(15), - previous_port: Some("COM7".to_string()), - requested_serial: Some("serial".to_string()), - candidates: Vec::new(), - })), - Duration::from_secs(15), - ) - .unwrap(); + let outcome = resolve_post_flash_cdc( + true, + Err(CdcWaitError::Timeout(CdcWaitTimeout { + elapsed: Duration::from_secs(15), + previous_port: Some("COM7".to_string()), + requested_serial: Some("serial".to_string()), + candidates: Vec::new(), + })), + Duration::from_secs(15), + ) + .unwrap(); let PostFlashCdc::Unconfirmed(note) = outcome else { panic!("expected an unconfirmed-CDC downgrade, got {outcome:?}"); }; @@ -2203,16 +2201,18 @@ mod tests { None, &BTreeSet::new(), Duration::ZERO, - || Ok(vec![ - PicoCdcPort { - name: "COM12".to_string(), - serial_number: None, - }, - PicoCdcPort { - name: "COM13".to_string(), - serial_number: None, - }, - ]), + || { + Ok(vec![ + PicoCdcPort { + name: "COM12".to_string(), + serial_number: None, + }, + PicoCdcPort { + name: "COM13".to_string(), + serial_number: None, + }, + ]) + }, || Duration::ZERO, |_| {}, );