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: 0 additions & 1 deletion .github/workflows/nightly-platforms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ jobs:
guard:
name: Guard (skip on quiet days)
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
Expand Down
22 changes: 17 additions & 5 deletions crates/fbuild-cli/src/cli/clangd_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,18 +318,30 @@ mod tests {
);
}

// The Windows-input arms of these two tests feed a raw `C:\tc\...`
// literal through `NormalizedPath::display_slash()`, which only
// converts `\` → `/` on Windows targets. On Linux, `\` is a valid
// filename byte, so the normalizer leaves it alone and the asserted
// `"C:/tc/bin/*"` shape never materializes. Gate the Windows arms
// behind `#[cfg(windows)]` and keep the POSIX arm portable.
#[test]
fn query_driver_glob_uses_bin_dir_forward_slashes() {
assert_eq!(
compiler_query_driver_glob(r"C:\tc\bin\avr-g++.exe"),
"C:/tc/bin/*"
);
fn query_driver_glob_uses_bin_dir_forward_slashes_posix() {
assert_eq!(
compiler_query_driver_glob("/home/u/.platformio/packages/tc/bin/arm-none-eabi-g++"),
"/home/u/.platformio/packages/tc/bin/*"
);
}

#[cfg(windows)]
#[test]
fn query_driver_glob_uses_bin_dir_forward_slashes_windows() {
assert_eq!(
compiler_query_driver_glob(r"C:\tc\bin\avr-g++.exe"),
"C:/tc/bin/*"
);
}

#[cfg(windows)]
#[test]
fn clangd_yaml_mentions_compiler_and_database() {
let yaml = render_clangd_yaml(r"C:\tc\bin\avr-g++");
Expand Down
1 change: 1 addition & 0 deletions crates/fbuild-cli/src/cli/sync_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::path::PathBuf;
use crate::sync::{run_sync, SyncArgs, SyncOutcome};

/// Adapter for `Commands::Sync` — invoked from `cli::dispatch`.
#[allow(clippy::too_many_arguments)] // Matches clap's parsed variant fields 1:1.
pub async fn run_sync_cmd(
project_dir: Option<PathBuf>,
environment: Option<String>,
Expand Down
9 changes: 5 additions & 4 deletions crates/fbuild-cli/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,11 @@ async fn do_run_sync(args: SyncArgs) -> Result<SyncOutcome, SyncError> {
let selected_envs = select_envs(&all_envs, args.environment.as_deref())?;

// Multi-env prompt (skipped by --yes / --check / -e <env>).
if selected_envs.len() > 1 && !args.skip_multi_env_prompt() {
if !prompt_multi_env(&selected_envs) {
return Ok(SyncOutcome::UserCancelled);
}
if selected_envs.len() > 1
&& !args.skip_multi_env_prompt()
&& !prompt_multi_env(&selected_envs)
{
return Ok(SyncOutcome::UserCancelled);
}

// Classify every env's lib_deps.
Expand Down
19 changes: 13 additions & 6 deletions crates/fbuild-cli/src/sync/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,12 @@ pub fn classify(raw: &str) -> ClassifiedDep {
};
}

// 4. HTTP/HTTPS — could be GitHub or a plain archive.
if trimmed.starts_with("http://") || trimmed.starts_with("https://") {
// 4. HTTP/HTTPS — could be GitHub or a plain archive. Case-insensitive
// on the scheme because PlatformIO's `lib_deps` treats URLs as
// URIs per RFC 3986 §3.1 (scheme is case-insensitive), and the
// `github_case_insensitive_host` test expects `HTTPS://GITHUB.COM/...`
// to still classify as Github.
if starts_with_ci(trimmed, "http://") || starts_with_ci(trimmed, "https://") {
// Split off the optional `#<ref>` (only meaningful for repo URLs;
// if it's on an archive URL it's harmless noise).
let (url_no_ref, hash_suffix) = split_ref(trimmed);
Expand Down Expand Up @@ -227,14 +231,17 @@ pub fn classify(raw: &str) -> ClassifiedDep {

// ---------- helpers ----------

/// ASCII case-insensitive `starts_with`, used for the RFC 3986 URI
/// scheme prefix check in `classify()`.
fn starts_with_ci(s: &str, prefix: &str) -> bool {
s.len() >= prefix.len() && s.as_bytes()[..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
}

/// Take the last `/` or `\` segment of a string, trimming any trailing
/// `.git`. Never returns empty — falls back to the input.
fn last_segment(s: &str) -> &str {
let end = s.trim_end_matches(['/', '\\']);
let seg = end
.rsplit(|c| c == '/' || c == '\\')
.next()
.unwrap_or(end);
let seg = end.rsplit(['/', '\\']).next().unwrap_or(end);
let seg = seg.trim_end_matches(".git");
if seg.is_empty() {
end
Expand Down
19 changes: 14 additions & 5 deletions crates/fbuild-cli/src/update_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,9 +736,16 @@ mod tests {

#[test]
fn ci_detection_via_ci_env() {
// Snapshot env to restore after test.
let saved = std::env::var("CI").ok();
// Snapshot + clear ALL CI markers we recognize, not just CI —
// otherwise GitHub Actions' own GITHUB_ACTIONS=true poisons the
// `assert!(!is_ci_env())` checks below.
const CI_KEYS: &[&str] = &["CI", "GITHUB_ACTIONS", "GITLAB_CI", "CIRCLECI", "JENKINS_URL"];
let saved: Vec<(&str, Option<String>)> =
CI_KEYS.iter().map(|k| (*k, std::env::var(*k).ok())).collect();
// SAFETY: single-threaded test process.
for k in CI_KEYS {
std::env::remove_var(k);
}
std::env::set_var("CI", "true");
assert!(is_ci_env());
std::env::set_var("CI", "0");
Expand All @@ -748,9 +755,11 @@ mod tests {
std::env::remove_var("CI");
assert!(!is_ci_env());
// Restore.
match saved {
Some(v) => std::env::set_var("CI", v),
None => std::env::remove_var("CI"),
for (k, v) in saved {
match v {
Some(val) => std::env::set_var(k, val),
None => std::env::remove_var(k),
}
}
}
}
6 changes: 4 additions & 2 deletions crates/fbuild-serial/src/boards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,8 +1135,10 @@ mod tests {
// No protocol string, but the touch flag is a strong
// ecosystem-standard signal in its own right (every product
// shipping this flag semantically means "1200-bps touch reset").
let mut h = UploadHint::default();
h.use_1200bps_touch = Some(true);
let h = UploadHint {
use_1200bps_touch: Some(true),
..Default::default()
};
assert_eq!(
family_from_upload_hint(&h),
Some(BoardFamily::NativeUsbCdcReset1200Bps)
Expand Down
4 changes: 2 additions & 2 deletions crates/fbuild-serial/src/port_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ mod linux {

/// Strip `/dev/` (or `/devices/` in some odd configurations) and
/// return the bare port name, e.g. `ttyACM0`.
fn port_name_stem(port_name: &str) -> Option<&str> {
pub(super) fn port_name_stem(port_name: &str) -> Option<&str> {
if let Some(stem) = port_name.strip_prefix("/dev/") {
return Some(stem);
}
Expand Down Expand Up @@ -220,7 +220,7 @@ mod linux {
}

#[cfg(test)]
pub(crate) use port_name_stem as port_name_stem_for_tests;
pub(super) use port_name_stem as port_name_stem_for_tests;
}

#[cfg(target_os = "macos")]
Expand Down
Loading