Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ exclude = [
"dylints/ban_file_based_locks",
"dylints/ban_deploy_tool_direct_invocation",
"dylints/ban_process_exit_outside_main",
"dylints/ban_unwrap_in_daemon_handlers",
"dylints/ban_unwrap_in_production",
"dylints/cli_no_build_deploy_direct_use",
"dylints/require_multi_thread_flavor_when_spawning",
"dylints/ban_std_sync_mutex_in_async",
Expand Down
2 changes: 1 addition & 1 deletion ci/hooks/crate_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"dylints/ban_file_based_locks",
"dylints/ban_deploy_tool_direct_invocation",
"dylints/ban_process_exit_outside_main",
"dylints/ban_unwrap_in_daemon_handlers",
"dylints/ban_unwrap_in_production",
"dylints/cli_no_build_deploy_direct_use",
"dylints/require_multi_thread_flavor_when_spawning",
"dylints/ban_std_sync_mutex_in_async",
Expand Down
9 changes: 7 additions & 2 deletions crates/fbuild-build/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,12 @@ fn looks_like_absolute_path(path: &Path, raw: &str) -> bool {

fn compiler_identity(path: &Path) -> String {
let cache = COMPILER_IDENTITY_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
if let Some(identity) = cache.lock().unwrap().get(path).cloned() {
if let Some(identity) = cache
.lock()
.unwrap_or_else(|e| e.into_inner())
.get(path)
.cloned()
{
return identity;
}

Expand All @@ -437,7 +442,7 @@ fn compiler_identity(path: &Path) -> String {
let identity = format!("{stem}\0{version}");
cache
.lock()
.unwrap()
.unwrap_or_else(|e| e.into_inner())
.insert(path.to_path_buf(), identity.clone());
identity
}
Expand Down
4 changes: 3 additions & 1 deletion crates/fbuild-build/src/esp32/orchestrator/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,9 @@ impl BuildOrchestrator for Esp32Orchestrator {
};

// Unwrap build log and flush collected warnings
let mut build_log = build_log_mutex.into_inner().unwrap();
let mut build_log = build_log_mutex
.into_inner()
.unwrap_or_else(|e| e.into_inner());
for w in core_result.warnings.iter().chain(&sketch_result.warnings) {
crate::build_output::collect_warnings(w, &mut build_log);
}
Expand Down
4 changes: 2 additions & 2 deletions crates/fbuild-build/src/pipeline/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub async fn compile_sources(
)
.await?;
if !result.warnings.is_empty() {
let mut log = build_log.lock().unwrap();
let mut log = build_log.lock().unwrap_or_else(|e| e.into_inner());
for w in &result.warnings {
crate::build_output::collect_warnings(w, &mut log);
}
Expand Down Expand Up @@ -106,7 +106,7 @@ pub async fn compile_local_libraries(
})?;
library_objects.extend(result.objects);
if !result.warnings.is_empty() {
let mut log = build_log.lock().unwrap();
let mut log = build_log.lock().unwrap_or_else(|e| e.into_inner());
for w in &result.warnings {
crate::build_output::collect_warnings(w, &mut log);
}
Expand Down
4 changes: 3 additions & 1 deletion crates/fbuild-build/src/pipeline/sequential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ pub async fn run_sequential_build_with_libs(

// Unwrap the build log Mutex back into the context for the remaining
// single-threaded phases (link, result assembly).
ctx.build_log = build_log_mutex.into_inner().unwrap();
ctx.build_log = build_log_mutex
.into_inner()
.unwrap_or_else(|e| e.into_inner());

// Project-as-library: compile project root's src/ as an archive when
// building an example sketch from a library project (e.g. FastLED examples).
Expand Down
5 changes: 4 additions & 1 deletion crates/fbuild-cli/src/cli/bloat_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ pub async fn run_bloat_lookup(
};
let report = analyze_elf(cfg).await?;

let query_str = symbol.clone().or_else(|| symbol_mangled.clone()).unwrap();
let query_str = symbol
.clone()
.or_else(|| symbol_mangled.clone())
.expect("fbuild-cli: bloat_lookup guards that symbol or symbol_mangled is Some");
let query = match (&symbol, &symbol_mangled) {
(Some(s), _) => SymbolQuery::SubstringDemangled(s),
(None, Some(m)) => SymbolQuery::ExactMangled(m),
Expand Down
10 changes: 8 additions & 2 deletions crates/fbuild-cli/src/cli/clang_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,10 @@ pub async fn run_iwyu(
let emap = entry_map_arc.clone();
let verbose_flag = verbose;
let handle = tokio::spawn(async move {
let _permit = sem.acquire().await.unwrap();
let _permit = sem
.acquire()
.await
.expect("fbuild-cli: clang-tool semaphore is never closed before all tasks finish");
let src_path = src.as_ref().clone();

// Compute blake3 cache key from source content + compile entry
Expand Down Expand Up @@ -570,7 +573,10 @@ pub async fn run_clang_tool(
let pd = project_dir_arc.clone();
let extra = extra_owned.clone();
let handle = tokio::spawn(async move {
let _permit = sem.acquire().await.unwrap();
let _permit = sem
.acquire()
.await
.expect("fbuild-cli: clang-tool semaphore is never closed before all tasks finish");
// allow-direct-spawn: parallel async fan-out (clang-tidy) in CLI binary.
let mut cmd = tokio::process::Command::new(tool.as_ref());
cmd.arg("-p").arg(pd.as_ref());
Expand Down
6 changes: 5 additions & 1 deletion crates/fbuild-cli/src/lib_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,5 +427,9 @@ fn emit_json(
"unresolved": sel.unresolved,
});

println!("{}", serde_json::to_string_pretty(&payload).unwrap());
println!(
"{}",
serde_json::to_string_pretty(&payload)
.expect("fbuild-cli: lib-select JSON payload is built from primitives, serialization is infallible")
);
}
4 changes: 3 additions & 1 deletion crates/fbuild-cli/src/mcp/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ pub async fn run_mcp_server() -> i32 {
continue;
}

let id = request.id.unwrap();
let id = request
.id
.expect("fbuild-cli: notification (id.is_none()) handled above; id is Some here");
let params = request.params.unwrap_or(Value::Null);

let response = match request.method.as_str() {
Expand Down
13 changes: 11 additions & 2 deletions crates/fbuild-config/src/bin/enrich_boards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,13 @@ fn enrich_board(board_path: &Path, pio_dir: &Path) -> Result<bool, String> {
let board_id = obj
.get("id")
.and_then(|v| v.as_str())
.unwrap_or_else(|| board_path.file_stem().unwrap().to_str().unwrap());
.unwrap_or_else(|| {
board_path
.file_stem()
.expect("fbuild-config: board JSON path always has a file stem")
.to_str()
.expect("fbuild-config: board JSON file stems are ASCII")
});
let platform = obj.get("platform").and_then(|v| v.as_str()).unwrap_or("");

if platform.is_empty() {
Expand Down Expand Up @@ -340,7 +346,10 @@ fn main() {
Err(e) => {
eprintln!(
" Error enriching {}: {e}",
board_path.file_stem().unwrap().to_string_lossy()
board_path
.file_stem()
.expect("fbuild-config: board JSON path always has a file stem")
.to_string_lossy()
);
errors += 1;
}
Expand Down
3 changes: 2 additions & 1 deletion crates/fbuild-config/src/ini_parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ pub(super) fn substitute_vars(
sections: &HashMap<String, HashMap<String, String>>,
config: &HashMap<String, String>,
) -> HashMap<String, String> {
let re = Regex::new(r"\$\{([^}]+)\}").unwrap();
let re = Regex::new(r"\$\{([^}]+)\}")
.expect("fbuild-config: ini variable substitution regex is a valid pattern");
let max_depth = 10;
let mut result = config.clone();

Expand Down
2 changes: 1 addition & 1 deletion crates/fbuild-daemon/src/handlers/operations/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ pub async fn build(
axum::response::Response::builder()
.header("content-type", "application/x-ndjson")
.body(body)
.unwrap()
.expect("fbuild-daemon: static NDJSON response builder cannot fail")
.into_response()
} else {
// --- NON-STREAMING PATH (existing behavior) ---
Expand Down
2 changes: 1 addition & 1 deletion crates/fbuild-daemon/src/handlers/operations/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ pub async fn deploy(
&deploy_board_overrides,
Some(deploy_project.as_path()),
);
let avr_config = fbuild_build::avr::mcu_config::get_avr_config().unwrap();
let avr_config = fbuild_build::avr::mcu_config::get_avr_config()?;
let avrdude_params = fbuild_deploy::avr::AvrdudeParams {
default_programmer: avr_config.avrdude.default_programmer.clone(),
default_baud: avr_config.avrdude.default_baud.to_string(),
Expand Down
14 changes: 11 additions & 3 deletions crates/fbuild-daemon/src/handlers/websockets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,11 @@ async fn handle_serial_ws(mut socket: WebSocket, ctx: Arc<DaemonContext>) {
current_index: last_index,
};
if ws_sink
.send(Message::Text(serde_json::to_string(&coalesced).unwrap()))
.send(Message::Text(
serde_json::to_string(&coalesced).expect(
"fbuild-daemon: SerialServerMessage::Data serialization is infallible",
),
))
.await
.is_err()
{
Expand All @@ -471,7 +475,9 @@ async fn handle_serial_ws(mut socket: WebSocket, ctx: Arc<DaemonContext>) {
}
}
if ws_sink
.send(Message::Text(serde_json::to_string(&other).unwrap()))
.send(Message::Text(serde_json::to_string(&other).expect(
"fbuild-daemon: SerialServerMessage serialization is infallible",
)))
.await
.is_err()
{
Expand All @@ -488,7 +494,9 @@ async fn handle_serial_ws(mut socket: WebSocket, ctx: Arc<DaemonContext>) {
current_index: last_index,
};
if ws_sink
.send(Message::Text(serde_json::to_string(&coalesced).unwrap()))
.send(Message::Text(serde_json::to_string(&coalesced).expect(
"fbuild-daemon: SerialServerMessage::Data serialization is infallible",
)))
.await
.is_err()
{
Expand Down
8 changes: 6 additions & 2 deletions crates/fbuild-daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,12 @@ async fn main() {
.layer(
tower_http::cors::CorsLayer::new()
.allow_origin([
"http://localhost".parse().unwrap(),
"http://127.0.0.1".parse().unwrap(),
"http://localhost"
.parse()
.expect("fbuild-daemon: 'http://localhost' is a valid CORS origin"),
"http://127.0.0.1"
.parse()
.expect("fbuild-daemon: 'http://127.0.0.1' is a valid CORS origin"),
])
.allow_methods(tower_http::cors::Any)
.allow_headers(tower_http::cors::Any),
Expand Down
21 changes: 15 additions & 6 deletions crates/fbuild-deploy/src/esp32/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,16 @@ pub(super) fn resolve_esp_image_file_offset(firmware_bin: &[u8], load_addr: u32)
"firmware.bin ended before segment header".to_string(),
));
}
let seg_load_addr =
u32::from_le_bytes(firmware_bin[cursor..cursor + 4].try_into().unwrap());
let seg_len =
u32::from_le_bytes(firmware_bin[cursor + 4..cursor + 8].try_into().unwrap()) as usize;
let seg_load_addr = u32::from_le_bytes(
firmware_bin[cursor..cursor + 4]
.try_into()
.expect("fbuild-deploy: 4-byte slice converts to [u8; 4] (bounds checked above)"),
);
let seg_len = u32::from_le_bytes(
firmware_bin[cursor + 4..cursor + 8]
.try_into()
.expect("fbuild-deploy: 4-byte slice converts to [u8; 4] (bounds checked above)"),
) as usize;
let data_start = cursor + ESP_IMAGE_SEGMENT_HEADER_LEN;
let data_end = data_start + seg_len;
if data_end > firmware_bin.len() {
Expand Down Expand Up @@ -185,8 +191,11 @@ pub(super) fn repair_esp_image_checksum_and_hash(image: &mut [u8]) -> Result<()>
"firmware.bin ended before segment header".to_string(),
));
}
let seg_len =
u32::from_le_bytes(image[cursor + 4..cursor + 8].try_into().unwrap()) as usize;
let seg_len = u32::from_le_bytes(
image[cursor + 4..cursor + 8]
.try_into()
.expect("fbuild-deploy: 4-byte slice converts to [u8; 4] (bounds checked above)"),
) as usize;
let data_start = cursor + ESP_IMAGE_SEGMENT_HEADER_LEN;
let data_end = data_start + seg_len;
if data_end > image.len() {
Expand Down
8 changes: 6 additions & 2 deletions crates/fbuild-header-scan/src/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,15 @@ pub fn scan(src: &str) -> Vec<IncludeRef> {
&& !prev_is_ident_continuation
&& is_raw_string_open(bytes, i)
{
let open_quote = bytes[i..].iter().position(|&c| c == b'"').unwrap() + i;
let open_quote = bytes[i..]
.iter()
.position(|&c| c == b'"')
.expect("fbuild-header-scan: is_raw_string_open guarantees '\"' ahead")
+ i;
let paren = bytes[open_quote + 1..]
.iter()
.position(|&c| c == b'(')
.unwrap()
.expect("fbuild-header-scan: is_raw_string_open guarantees '(' after the opening quote")
+ open_quote
+ 1;
raw_delim.clear();
Expand Down
6 changes: 5 additions & 1 deletion crates/fbuild-paths/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,11 @@ pub fn find_firmware(
/// Like `find_firmware()` but returns the directory, not the file.
/// Useful when you need sibling files (bootloader.bin, partitions.bin).
pub fn find_firmware_dir(project_dir: &Path, env_name: &str) -> Option<PathBuf> {
find_firmware(project_dir, env_name, None).map(|p| p.parent().unwrap().to_path_buf())
find_firmware(project_dir, env_name, None).map(|p| {
p.parent()
.expect("fbuild-paths: find_firmware always returns a file under a directory")
.to_path_buf()
})
}

fn dirs_next() -> Option<PathBuf> {
Expand Down
6 changes: 4 additions & 2 deletions crates/fbuild-python/src/async_serial_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ impl AsyncSerialMonitor {
open_if_needed: true,
pre_acquire_writer: true,
};
let attach_json = serde_json::to_string(&attach).unwrap();
let attach_json = serde_json::to_string(&attach)
.expect("fbuild-python: ClientMessage::Attach serialization is infallible");

match tokio::time::timeout(
HANDSHAKE_TIMEOUT,
Expand Down Expand Up @@ -219,7 +220,8 @@ impl AsyncSerialMonitor {

pyo3_async_runtimes::tokio::future_into_py(py, async move {
if let Some(mut write) = ws_write_slot.lock().await.take() {
let detach = serde_json::to_string(&ClientMessage::Detach).unwrap();
let detach = serde_json::to_string(&ClientMessage::Detach)
.expect("fbuild-python: ClientMessage::Detach serialization is infallible");
let _ = write.send(tungstenite::Message::Text(detach)).await;
let _ = write.send(tungstenite::Message::Close(None)).await;
}
Expand Down
3 changes: 2 additions & 1 deletion crates/fbuild-python/src/json_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ pub(crate) async fn write_async(
ws_read_slot: Arc<tokio::sync::Mutex<Option<WsSource>>>,
encoded: String,
) -> bool {
let msg = serde_json::to_string(&ClientMessage::Write { data: encoded }).unwrap();
let msg = serde_json::to_string(&ClientMessage::Write { data: encoded })
.expect("fbuild-python: ClientMessage::Write serialization is infallible");

{
let mut guard = ws_write_slot.lock().await;
Expand Down
Loading
Loading