From 240783dd49d3c0502effbed6512a0fb5f8ecd723 Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 28 Aug 2026 18:07:24 +0200 Subject: [PATCH] hive-priv: require exactly one nix build output path, don't just trim --- hive-priv/src/main.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/hive-priv/src/main.rs b/hive-priv/src/main.rs index 0c5b9315..4f1dc185 100644 --- a/hive-priv/src/main.rs +++ b/hive-priv/src/main.rs @@ -816,10 +816,22 @@ async fn nix_build_toplevel(name: &str, mut writer: Option<&mut OwnedWriteHalf>) stderr_buf.lines().last().unwrap_or("").trim() ); } - let path = stdout_buf.trim(); - if path.is_empty() { - bail!("nix build {attr} produced no output path"); - } + // `--print-out-paths` prints one line *per output*, not one line + // total: `nix build --no-link --print-out-paths nixpkgs#openssl` + // prints two (`…-bin`, `…-man`). `config.system.build.toplevel` is + // single-output today, so this is one line in practice — but a bare + // `.trim()` would silently hand a multi-line string on to + // `--system-path` the day that ever changes, which is the same + // corrupted-argument failure this function exists to avoid. Require + // exactly one line and error otherwise, so a future multi-output + // attr fails loudly here instead of downstream in `nixos-container`. + let lines: Vec<&str> = stdout_buf.lines().collect(); + let [path] = lines[..] else { + bail!( + "nix build {attr} produced {} output path(s), expected exactly 1: {stdout_buf:?}", + lines.len() + ); + }; Ok(path.to_owned()) }