fix(firmware): recover git_sync from a leftover clone dir

859c478 aborted if /spiflash/repo already existed — libgit2 refuses to
clone into a non-empty dir (code=Exists). Remove a writable stale/partial
clone and re-clone.

Milestone #2A now hardware-verified end to end: clone (boot 1) + persistent
open + fast-forward push (boot 2) against origin/main, on the 96 KB git
thread, min heap 6.8 MB — clone/checkout fit the stack, no bump needed.

Known limit: the remove only works on a *writable* leftover. libgit2 marks
objects/packs read-only and FATFS won't f_unlink a read-only file (EACCES);
POSIX chmod does not clear AM_RDO on esp-idf's FATFS VFS (verified). So
re-cloning over a run that wrote objects needs an AM_RDO-clearing unlink
shim in esp_stubs.c (increment B, also needed for fetch/repack); until then
the fallback is a one-time `espflash erase-region 0x310000 0x400000`.
This commit is contained in:
Julien Calixte
2026-07-07 08:34:09 +02:00
parent 859c4787cf
commit afa61deaa6

View File

@@ -241,13 +241,33 @@ fn open_or_clone() -> Result<(Repository, bool)> {
Ok((repo, false))
}
Err(_) => {
log::info!("no repo at {REPO_DIR} — cloning {REMOTE_URL}");
// A leftover at REPO_DIR is a partial clone (libgit2 refuses to clone
// into a non-empty dir, code=Exists). Remove it and re-clone. NOTE:
// this only succeeds if the leftover is writable — libgit2 marks
// objects/packs read-only, FATFS won't f_unlink a read-only file
// (EACCES), and POSIX chmod does NOT clear the attribute on esp-idf's
// FATFS VFS (verified on hardware). So a clone that got far enough to
// write objects can't be cleared from here yet; the proper fix is an
// AM_RDO-clearing unlink shim in esp_stubs.c (increment B, needed for
// fetch/repack too). Until then the fallback is a one-time wipe:
// `espflash erase-region 0x310000 0x400000`.
if Path::new(REPO_DIR).exists() {
log::warn!("{REPO_DIR} exists but is not a valid repo — removing stale clone");
fs::remove_dir_all(REPO_DIR).with_context(|| {
format!(
"removing stale {REPO_DIR} — if this is EACCES (read-only files on \
FATFS), erase the storage partition once: \
`espflash erase-region 0x310000 0x400000`"
)
})?;
}
log::info!("cloning {REMOTE_URL} → {REPO_DIR}");
let mut fo = FetchOptions::new();
fo.remote_callbacks(auth_callbacks());
let repo = RepoBuilder::new()
.fetch_options(fo)
.clone(REMOTE_URL, Path::new(REPO_DIR))
.context("clone (is REPO_DIR a leftover partial clone? it must not exist)")?;
.context("clone")?;
Ok((repo, true))
}
}