Watch
0
0
Fork
You've already forked hyperhive
0

leave the old applied dirs alone: no startup deletion. Refs #5913

This commit is contained in:
damocles 2026-11-01 17:49:06 +01:00
commit c39a836bc5

View file

@ -1,5 +1,5 @@
//! Startup convergence. Three phases, all idempotent and unguarded:
//! harness files, the leftover applied repos, the agent-set files, plus the
//! Startup convergence. Two phases, all idempotent and unguarded:
//! harness files and the agent-set files, plus the
//! removal of the legacy meta repo's leftovers. They re-run every
//! boot on purpose — each one is a no-op once its state is already
//! correct.
@ -72,16 +72,8 @@ pub async fn run() -> Result<()> {
Err(e) => tracing::warn!(error = ?e, "migration: removing the legacy meta .git failed"),
}
// Phase 1: the applied repos an earlier hive kept per agent.
tracing::debug!("migration: phase 1 (leftover applied repos)");
match remove_applied_repos(&crate::paths::applied_root()) {
Ok(0) => {}
Ok(n) => tracing::info!(count = n, "migration: removed leftover applied repos"),
Err(e) => tracing::warn!(error = ?e, "migration: removing the applied repos failed"),
}
// Phase 2: the files that follow the agent set.
tracing::debug!("migration: phase 2 (agent_set refresh)");
// Phase 1: the files that follow the agent set.
tracing::debug!("migration: phase 1 (agent_set refresh)");
// `refresh` takes the agents it is given as the whole set, so an empty
// stand-in for an unreadable list would drop every agent from the topology.
let agents = match lifecycle::agents_for_meta_listing().await {
@ -167,29 +159,6 @@ async fn enumerate_agents() -> Result<Vec<hive_types::Ident>> {
.collect())
}
/// Remove the per-agent `applied/<name>` repos an earlier hive kept in `root`,
/// destroyed agents' included. The forge's `agent-configs/<name>` is the only
/// copy of a config now, so nothing reads them. The dot-files beside them (the
/// deploy markers) stay. Returns how many it removed.
fn remove_applied_repos(root: &Path) -> Result<usize> {
let entries = match std::fs::read_dir(root) {
Ok(entries) => entries,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(0),
Err(e) => return Err(e).with_context(|| format!("reading {}", root.display())),
};
let mut removed = 0;
for entry in entries {
let entry = entry.with_context(|| format!("reading {}", root.display()))?;
if !entry.file_type()?.is_dir() {
continue;
}
let path = entry.path();
std::fs::remove_dir_all(&path).with_context(|| format!("removing {}", path.display()))?;
removed += 1;
}
Ok(removed)
}
#[cfg(test)]
mod tests {
use super::*;
@ -231,30 +200,4 @@ mod tests {
assert!(dir.path().join("forge-other").exists(), "neighbour stays");
assert!(!remove_core_token(dir.path()).expect("second"), "no-op");
}
#[test]
fn applied_repos_go_and_the_markers_beside_them_stay() {
let root = tempfile::tempdir().expect("tempdir");
for name in ["alice", "bob"] {
std::fs::create_dir_all(root.path().join(name).join(".git")).expect("mkdir repo");
std::fs::write(root.path().join(name).join("agent.nix"), "{}").expect("write config");
std::fs::write(root.path().join(format!(".{name}.config-rev")), "abc").expect("marker");
}
assert_eq!(remove_applied_repos(root.path()).expect("first"), 2);
assert!(!root.path().join("alice").exists());
assert!(
root.path().join(".alice.config-rev").exists(),
"marker stays"
);
assert_eq!(
remove_applied_repos(root.path()).expect("second"),
0,
"no-op"
);
assert_eq!(
remove_applied_repos(&root.path().join("missing")).expect("absent root"),
0
);
}
}