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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ exclude = [
"dylints/cli_no_build_deploy_direct_use",
"dylints/require_multi_thread_flavor_when_spawning",
"dylints/ban_std_sync_mutex_in_async",
# FastLED/fbuild#844 bridge sweep — 10 net-new lints landing
# together with the matching internal bridge APIs.
"dylints/ban_bare_reqwest",
"dylints/ban_std_fs_in_async",
"dylints/ban_tokio_fs_direct_import",
"dylints/ban_std_thread_sleep",
"dylints/ban_std_mpsc_in_async_reachable",
"dylints/ban_tokio_mpsc_direct_import",
"dylints/ban_std_fs_canonicalize",
"dylints/ban_runtime_new_outside_main",
"dylints/ban_poison_panic",
"dylints/ban_print_in_production",
]

[workspace.metadata.dylint]
Expand Down
14 changes: 14 additions & 0 deletions ci/hooks/crate_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@
"dylints/cli_no_build_deploy_direct_use",
"dylints/require_multi_thread_flavor_when_spawning",
"dylints/ban_std_sync_mutex_in_async",
# FastLED/fbuild#844 bridge sweep — 10 new dylints landing
# together with the matching internal bridge APIs in
# fbuild-core (http, fs, time, channel, path::canonicalize_existing)
# and fbuild-cli/src/output.rs.
"dylints/ban_bare_reqwest",
"dylints/ban_std_fs_in_async",
"dylints/ban_tokio_fs_direct_import",
"dylints/ban_std_thread_sleep",
"dylints/ban_std_mpsc_in_async_reachable",
"dylints/ban_tokio_mpsc_direct_import",
"dylints/ban_std_fs_canonicalize",
"dylints/ban_runtime_new_outside_main",
"dylints/ban_poison_panic",
"dylints/ban_print_in_production",
}
)

Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/avr/avr_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,7 @@ impl Linker for AvrLinker {
let args = self.build_link_args(objects, &linker_archives, output_dir, &elf_path, extra);

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::avr", "link: {}", args.join(" "));
}

let args_ref: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
Expand Down
19 changes: 18 additions & 1 deletion crates/fbuild-build/src/build_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,24 @@ pub fn emit_build_info(project_dir: &Path, env_name: &str, info: &BuildInfo) ->
continue;
}
}
if let Err(e) = std::fs::write(path, &json) {
// Atomic write — FastLED/fbuild#844 bridge pair 6.
// `emit_build_info` is a sync function called from sync build
// pipeline code, but always under the daemon's tokio runtime.
// Bridge to the async `write_atomic` via `block_in_place`. Same
// pattern as `fbuild_packages::toolchain::esp32_metadata`.
let write_res =
if let Ok(handle) = tokio::runtime::Handle::try_current() {
tokio::task::block_in_place(|| {
handle.block_on(fbuild_core::fs::write_atomic(path, json.as_bytes()))
})
} else {
// No runtime — happens in unit tests of this module.
// Fall back to plain `std::fs::write`; the integration
// path always has a runtime so the atomic guarantee is
// preserved where it matters.
std::fs::write(path, &json)
};
if let Err(e) = write_res {
tracing::warn!("failed to write {}: {}", path.display(), e);
}
}
Expand Down
7 changes: 3 additions & 4 deletions crates/fbuild-build/src/build_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
use std::path::Path;
use std::time::Instant;

use fbuild_core::channel::UnboundedSender;
use fbuild_core::{BuildLog, MemoryRegion, SizeInfo, SymbolMap};

/// Create a [`BuildLog`], optionally wired to a real-time streaming sender.
pub fn create_build_log(
sender: Option<tokio::sync::mpsc::UnboundedSender<String>>,
) -> BuildLog {
pub fn create_build_log(sender: Option<UnboundedSender<String>>) -> BuildLog {
match sender {
Some(s) => BuildLog::with_sender(s),
None => BuildLog::new(),
Expand All @@ -21,7 +20,7 @@ pub fn create_build_log(

/// Create a [`BuildLog`] with elapsed-time prefixes from the given epoch.
pub fn create_build_log_with_epoch(
sender: Option<tokio::sync::mpsc::UnboundedSender<String>>,
sender: Option<UnboundedSender<String>>,
epoch: Instant,
) -> BuildLog {
match sender {
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/ch32v/ch32v_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ impl Linker for Ch32vLinker {
args.extend(extra.libs.iter().cloned());

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::ch32v", "link: {}", args.join(" "));
}

let args_ref: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/esp8266/esp8266_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,7 @@ impl Linker for Esp8266Linker {
args.push("-Wl,--end-group".to_string());

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::esp8266", "link: {}", args.join(" "));
}

let args_ref: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/generic_arm/arm_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ impl Linker for ArmLinker {
let args = self.build_link_args(objects, archives, &elf_path, &map_path, extra);

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::generic_arm", "link: {}", args.join(" "));
}

// GCC LTO temp dir for MSYS-safe paths — see FastLED/fbuild#261.
Expand Down
11 changes: 7 additions & 4 deletions crates/fbuild-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,15 @@ pub struct BuildParams {
pub compiledb_only: bool,
/// Optional sender for streaming build log lines in real-time.
///
/// Uses `tokio::sync::mpsc::UnboundedSender` so the orchestrator (running
/// on a tokio runtime) and the WebSocket forwarder can share one channel
/// Uses `fbuild_core::channel::UnboundedSender` (the workspace bridge over
/// `tokio::sync::mpsc::UnboundedSender`) so the orchestrator (running on a
/// tokio runtime) and the WebSocket forwarder can share one channel
/// without a sync→async bridge — `UnboundedSender::send` is sync and safe
/// to call from blocking code, while the receive side is awaited from the
/// async daemon handler (fbuild#818).
pub log_sender: Option<tokio::sync::mpsc::UnboundedSender<String>>,
/// async daemon handler (fbuild#818). Routed via `fbuild_core::channel`
/// to satisfy the workspace `ban_tokio_mpsc_direct_import` dylint
/// (fbuild#844).
pub log_sender: Option<fbuild_core::channel::UnboundedSender<String>>,
/// When true, run symbol-level memory analysis after linking.
pub symbol_analysis: bool,
/// Optional path to write the symbol analysis report to.
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/nrf52/nrf52_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ impl Linker for Nrf52Linker {
args.extend(extra.libs.iter().cloned());

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::nrf52", "link: {}", args.join(" "));
}

// GCC LTO temp dir for MSYS-safe paths — see FastLED/fbuild#261.
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/renesas/renesas_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ impl Linker for RenesasLinker {
args.extend(extra.libs.iter().cloned());

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::renesas", "link: {}", args.join(" "));
}

// GCC LTO temp dir for MSYS-safe paths — see FastLED/fbuild#261.
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/sam/sam_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ impl Linker for SamLinker {
args.extend(extra.libs.iter().cloned());

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::sam", "link: {}", args.join(" "));
}

// GCC LTO temp dir for MSYS-safe paths — see FastLED/fbuild#261.
Expand Down
16 changes: 10 additions & 6 deletions crates/fbuild-build/src/script_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,16 @@ pub async fn resolve_extra_script_overlay(
)
})?;

let temp_dir = tempfile::tempdir().map_err(|e| {
fbuild_core::FbuildError::BuildFailed(format!(
"failed to create temporary directory for extra_scripts runtime: {}",
e
))
})?;
// FastLED/fbuild#844 (bridge pair 10): rooted under
// `~/.fbuild/{dev|prod}/tmp/script-runtime/` so the harness sidecar
// is reachable from a single user-visible directory.
let temp_dir =
tempfile::tempdir_in(fbuild_paths::temp_subdir("script-runtime")).map_err(|e| {
fbuild_core::FbuildError::BuildFailed(format!(
"failed to create temporary directory for extra_scripts runtime: {}",
e
))
})?;
let harness_path = temp_dir.path().join("fbuild_lite_scons_harness.py");
let input_path = temp_dir.path().join("input.json");
std::fs::write(&harness_path, HARNESS).map_err(|e| {
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/silabs/silabs_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,7 @@ impl Linker for SilabsLinker {
args.push("-Wl,--end-group".to_string());

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::silabs", "link: {}", args.join(" "));
}

// GCC LTO temp dir for MSYS-safe paths — see FastLED/fbuild#261.
Expand Down
3 changes: 1 addition & 2 deletions crates/fbuild-build/src/teensy/teensy_linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,7 @@ impl Linker for TeensyLinker {
let args = self.build_link_args(objects, archives, &elf_path, extra);

if self.verbose {
eprintln!("link: {}", args.join(" "));
tracing::info!("link: {}", args.join(" "));
tracing::debug!(target: "fbuild_build::linker::teensy", "link: {}", args.join(" "));
}

// Redirect GCC LTO temp files into a forward-slashed, fbuild-owned
Expand Down
24 changes: 15 additions & 9 deletions crates/fbuild-cli/src/cli/bloat_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use fbuild_core::symbol_analysis::{
};
use fbuild_core::{FbuildError, Result};

use crate::output;

use super::symbols_cmd::resolve_tool_paths_public;

#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -81,30 +83,34 @@ pub async fn run_bloat_lookup(
match report.find_symbol(&query) {
SymbolLookup::Hit(sym) => {
if json {
let out = serde_json::to_string_pretty(sym)
let rendered = serde_json::to_string_pretty(sym)
.map_err(|e| FbuildError::Other(format!("json serialize: {e}")))?;
println!("{out}");
output::result(rendered);
} else {
print!("{}", format_symbol_block(sym, &report));
// format_symbol_block already terminates lines with '\n'; strip
// the trailing newline so result()'s newline doesn't double up.
output::result(format_symbol_block(sym, &report).trim_end_matches('\n'));
}
Ok(())
}
SymbolLookup::Ambiguous(candidates) => {
if json {
let payload: Vec<&FineGrainedSymbol> = candidates;
let out = serde_json::to_string_pretty(&payload)
let rendered = serde_json::to_string_pretty(&payload)
.map_err(|e| FbuildError::Other(format!("json serialize: {e}")))?;
println!("{out}");
output::result(rendered);
} else {
eprintln!(
output::error(format!(
"ambiguous: {} symbols match `{}`:",
candidates.len(),
query_str
);
));
for c in &candidates {
eprintln!(" {} B {}", c.size, c.demangled);
output::error(format!(" {} B {}", c.size, c.demangled));
}
eprintln!("re-run with a more specific --symbol value (or use --symbol-mangled).");
output::error(
"re-run with a more specific --symbol value (or use --symbol-mangled).",
);
}
Err(FbuildError::BuildFailed(format!(
"ambiguous symbol query `{query_str}`"
Expand Down
6 changes: 5 additions & 1 deletion crates/fbuild-cli/src/cli/bringup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ use clap::Args;
use fbuild_core::{FbuildError, Result};
use fbuild_serial::boards::{family_for_vid_pid, vcom_for_env, BoardFamily};

use crate::output;

/// `fbuild bringup` CLI args. Pluggable RPC method / payload /
/// expected-result, with per-board defaults supplied via the env
/// argument's board JSON (`bringup.{method, payload, expected_result}`).
Expand Down Expand Up @@ -161,7 +163,9 @@ impl std::fmt::Display for BringupResult {
/// Top-level entry — dispatcher calls this.
pub fn run_bringup(args: BringupArgs) -> Result<()> {
let result = run_bringup_inner(&args)?;
println!("{result}");
// BringupResult's Display impl already terminates with '\n'; strip the
// trailing newline so result()'s newline doesn't double up.
output::result(result.to_string().trim_end_matches('\n'));
if !result.is_passing() && !args.dry_run {
return Err(FbuildError::DeployFailed(format!(
"bring-up failed: {result}"
Expand Down
22 changes: 13 additions & 9 deletions crates/fbuild-cli/src/cli/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! `fbuild build` handler and a couple of path / browser helpers.

use crate::daemon_client::{self, BuildRequest, DaemonClient};
use crate::output;

pub async fn open_in_browser(url: &str) -> fbuild_core::Result<()> {
let args: Vec<&str> = if cfg!(target_os = "windows") {
Expand Down Expand Up @@ -67,14 +68,14 @@ pub async fn run_build(
.as_deref()
.or_else(|| config.get_default_environment())
.unwrap_or("default");
println!("Environment: {}", env_name);
println!("Daemon is running. Dry-run complete.");
output::result(format!("Environment: {}", env_name));
output::result("Daemon is running. Dry-run complete.");
return Ok(());
}

let client = DaemonClient::new();
if verbose {
eprintln!("{}", daemon_client::runtime_diagnostic());
output::debug(daemon_client::runtime_diagnostic());
}

let profile = if release {
Expand All @@ -87,10 +88,10 @@ pub async fn run_build(
let generate_compiledb = target.as_deref() == Some("compiledb");
if generate_compiledb {
let env_label = environment.as_deref().unwrap_or("default");
println!(
output::progress(format!(
"Generating compile_commands.json for environment: {}...",
env_label
);
));
}
let (caller_pid, caller_cwd) = daemon_client::caller_info();
let req = BuildRequest {
Expand Down Expand Up @@ -121,7 +122,7 @@ pub async fn run_build(
let resp = client.build_streaming(&req).await?;
let stream_elapsed = stream_start.elapsed();
if !resp.message.is_empty() {
println!("{}", resp.message);
output::result(&resp.message);
}
if perf_enabled {
let summary = format!(
Expand All @@ -131,18 +132,21 @@ pub async fn run_build(
cli_start.elapsed().as_millis(),
);
tracing::info!(target: "fbuild_cli::perf_log", "{}", summary);
eprintln!("{}", summary);
output::debug(&summary);
}
if !resp.success {
if !verbose {
eprintln!("{}", daemon_client::runtime_diagnostic());
output::error(daemon_client::runtime_diagnostic());
}
std::process::exit(resp.exit_code);
}
if generate_compiledb {
let db_path = std::path::Path::new(&project_dir).join("compile_commands.json");
if db_path.exists() {
println!("compile_commands.json written to {}", db_path.display());
output::result(format!(
"compile_commands.json written to {}",
db_path.display()
));
}
}
Ok(())
Expand Down
Loading
Loading