Skip to content

Commit 33e1890

Browse files
redsun82Copilot
andcommitted
fix(rust): backdate extracted CLI mtime to stop self-invalidation
When `bundled-cli` is off, `build.rs` watches the extracted CLI binary via `cargo:rerun-if-changed` so a deleted cache binary forces a re-extract. On a cold cache the same build script *creates* that binary mid-build, after the download — so its mtime ends up newer than cargo's build-script `output` reference (stamped when the script was spawned). The next identical `cargo` invocation then sees the watched file as "changed", reruns build.rs, recompiles the SDK crate, and relinks every downstream crate (observed ~9 min of wasted CI on a second cargo invocation in the same job). Backdate the staged binary's mtime to the Unix epoch before the atomic rename (rename preserves mtime), so it lands unambiguously older than any real build reference and a no-change rebuild stays a true no-op. Best-effort: on error we emit a `cargo:warning` and continue, reverting to the prior redundant-rebuild behaviour rather than breaking the build. The deleted-file recovery contract is untouched — a missing file still can't be stat'd, so cargo still reruns. Embed mode (`bundled-cli` on) is unaffected: it emits no `rerun-if-changed` on any build-created file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0667a46 commit 33e1890

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

rust/build.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,35 @@ fn extract_to_cache(archive: &[u8], install_dir: &Path, platform: Platform) -> P
378378
}
379379
}
380380

381+
// Backdate the staged binary to the Unix epoch before it lands. We emit
382+
// `cargo:rerun-if-changed` on `final_path` (see caller) so a *deleted*
383+
// cache binary forces a re-extract — but cargo stamps the build-script
384+
// `output` reference when the script is spawned, seconds before this
385+
// freshly-downloaded binary is written. A current mtime would therefore
386+
// be *newer* than that reference, so the next identical `cargo`
387+
// invocation would see the watched file as "changed" and pointlessly
388+
// rerun build.rs + recompile the crate + relink every downstream crate.
389+
// Pinning to the epoch keeps the file unambiguously older than any real
390+
// build reference; `rename` preserves mtime (same inode), so it lands
391+
// already-backdated and a no-change rebuild stays a true no-op. The
392+
// deleted-file recovery contract is untouched: a missing file can't be
393+
// stat'd, so cargo still treats it as stale and reruns regardless.
394+
//
395+
// Best-effort: a filesystem that refuses the epoch (e.g. FAT's 1980 floor
396+
// clamps it — still older than any real reference) or rejects the call
397+
// just reverts to the pre-fix redundant-rebuild behaviour, never a broken
398+
// build.
399+
if let Err(e) = std::fs::File::options()
400+
.write(true)
401+
.open(&staging_path)
402+
.and_then(|f| f.set_modified(std::time::SystemTime::UNIX_EPOCH))
403+
{
404+
println!(
405+
"cargo:warning=Could not backdate {} (a redundant rebuild may occur): {e}",
406+
staging_path.display()
407+
);
408+
}
409+
381410
// Atomic file-replace on both Unix and Windows. If a concurrent build
382411
// already produced the same file the rename overwrites it; the bytes
383412
// are SHA-verified-identical so replacement is safe.

0 commit comments

Comments
 (0)