Watch
0
0
Fork
You've already forked hyperhive
0

migrate: an unreadable applied flake.nix fails that repo's migration instead of being overwritten

Only a missing file counts as 'marker absent'; any other read error (EACCES,
EIO, non-UTF-8) used to read as empty, so the agent's flake.nix was replaced
and committed.
This commit is contained in:
atlas 2026-10-16 13:46:05 +02:00 • committed by mara
commit ba1515aa5e

View file

@ -168,19 +168,29 @@ async fn enumerate_agents() -> Result<Vec<hive_types::Ident>> {
}
async fn migrate_applied_repo(name: &str) -> Result<()> {
let dir = crate::paths::applied_dir(name);
migrate_applied_dir(name, &crate::paths::applied_dir(name)).await
}
/// Rewrites the applied repo at `dir` to the module-only flake. A missing
/// `flake.nix` counts as "marker absent"; any other read error fails the
/// migration so the agent's file is never overwritten unread.
async fn migrate_applied_dir(name: &str, dir: &Path) -> Result<()> {
if !dir.join(".git").exists() {
return Ok(());
}
let flake_path = dir.join("flake.nix");
let cur = std::fs::read_to_string(&flake_path).unwrap_or_default();
let cur = match std::fs::read_to_string(&flake_path) {
Ok(cur) => cur,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => String::new(),
Err(e) => return Err(e).with_context(|| format!("read {}", flake_path.display())),
};
if cur.contains(MODULE_FLAKE_MARKER) {
return Ok(());
}
let want = lifecycle::initial_flake_nix();
std::fs::write(&flake_path, want).with_context(|| format!("write {}", flake_path.display()))?;
raw_git(
&dir,
dir,
&[
"-c",
"user.name=c0re",
@ -192,7 +202,7 @@ async fn migrate_applied_repo(name: &str) -> Result<()> {
)
.await?;
raw_git(
&dir,
dir,
&[
"-c",
"user.name=c0re",
@ -206,7 +216,7 @@ async fn migrate_applied_repo(name: &str) -> Result<()> {
.await?;
// Relocate deployed/0 to the migration commit so
// setup_applied's existence check passes.
raw_git(&dir, &["tag", "-f", "deployed/0", "HEAD"]).await?;
raw_git(dir, &["tag", "-f", "deployed/0", "HEAD"]).await?;
tracing::info!(%name, "migration: applied repo migrated to module-only flake");
Ok(())
}
@ -241,3 +251,22 @@ async fn raw_git(dir: &Path, args: &[&str]) -> Result<()> {
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn unreadable_flake_is_left_untouched() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::create_dir(dir.path().join(".git")).expect("mkdir .git");
let flake = dir.path().join("flake.nix");
let bytes = [0xff_u8, 0xfe, b'x'];
std::fs::write(&flake, bytes).expect("write flake");
let res = migrate_applied_dir("t", dir.path()).await;
assert!(res.is_err(), "non-UTF-8 flake.nix must fail the migration");
assert_eq!(std::fs::read(&flake).expect("read back"), bytes);
}
}