Watch
0
0
Fork
You've already forked hyperhive
0

forge seed: clear the whole applied dir when a seed fails, so the template starts from nothing

This commit is contained in:
damocles 2026-11-01 14:33:45 +01:00 • committed by mara
commit 41e6136caf

View file

@ -2,6 +2,8 @@
//! `agent-configs/<name>`. The typed API-client constructor + org-name //! `agent-configs/<name>`. The typed API-client constructor + org-name
//! constants live in the module root (`super`). //! constants live in the module root (`super`).
use std::path::Path;
use super::{CONFIG_ORG, forge_git_url, reader_token}; use super::{CONFIG_ORG, forge_git_url, reader_token};
/// Seed an agent's `applied` repo, missing its `.git` entirely (first spawn, /// Seed an agent's `applied` repo, missing its `.git` entirely (first spawn,
@ -15,7 +17,7 @@ use super::{CONFIG_ORG, forge_git_url, reader_token};
/// forge has no `main` for the agent yet (the normal case right after /// forge has no `main` for the agent yet (the normal case right after
/// `swarm-controller` creates it, before it has pushed anything), or any git /// `swarm-controller` creates it, before it has pushed anything), or any git
/// step fails. Callers fall back to the template or the original hard error. A /// step fails. Callers fall back to the template or the original hard error. A
/// failed seed leaves no `.git` behind, so a later "is it seeded" check reads /// failed seed leaves the directory empty, so a later "is it seeded" check reads
/// the same as before the attempt. Only `true` once `applied` is seeded and /// the same as before the attempt. Only `true` once `applied` is seeded and
/// tagged `deployed/0`. /// tagged `deployed/0`.
pub async fn fetch_config_main_into_applied(name: &str) -> bool { pub async fn fetch_config_main_into_applied(name: &str) -> bool {
@ -79,7 +81,42 @@ pub async fn fetch_config_main_into_applied(name: &str) -> bool {
} }
.await; .await;
if !seeded { if !seeded {
let _ = std::fs::remove_dir_all(applied.join(".git")); clear_dir(&applied);
} }
seeded seeded
} }
/// Empty `dir`, keeping the directory itself: a failed seed may have written
/// the working tree as well as the `.git`, and the template fallback must start
/// from nothing rather than adopt files that were meant for the forge's commit.
fn clear_dir(dir: &Path) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
let _ = if path.is_dir() {
std::fs::remove_dir_all(path)
} else {
std::fs::remove_file(path)
};
}
}
#[cfg(test)]
mod tests {
use super::clear_dir;
#[test]
fn clear_dir_empties_a_dir_but_keeps_it() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::create_dir(dir.path().join(".git")).expect("mkdir .git");
std::fs::write(dir.path().join(".git/HEAD"), "ref").expect("write HEAD");
std::fs::write(dir.path().join("agent.nix"), "{}").expect("write agent.nix");
clear_dir(dir.path());
assert!(dir.path().is_dir(), "the directory itself stays");
assert_eq!(std::fs::read_dir(dir.path()).expect("read_dir").count(), 0);
}
}