use std::path::Path;
const REV: &str = "ebec37af1821deadbeefcafe0123456789abcdef";
const SHORT_REV: &str = "ebec37a"; const LAST_MODIFIED: i64 = 1_700_000_000;
fn write(path: &Path, contents: &str) {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).unwrap();
}
std::fs::write(path, contents).unwrap();
}
fn build_fixture(root_dir: &Path) {
let child = root_dir.join("child");
write(
&child.join("flake.nix"),
r#"{
description = "child reads its own self-rev";
outputs = { self }: {
selfRev = self.rev or "NONE";
selfShortRev = self.shortRev or "NONE";
selfLastModified = self.lastModified or (-1);
};
}"#,
);
write(
&root_dir.join("flake.nix"),
r#"{
description = "root";
inputs.child.url = "path:./child";
outputs = { self, child }: {
childRev = child.selfRev;
childShortRev = child.selfShortRev;
childLastModified = child.selfLastModified;
};
}"#,
);
write(&root_dir.join("flake.lock"), &root_lock(&child));
}
fn root_lock(child: &Path) -> String {
serde_json::json!({
"nodes": {
"child": {
"flake": true,
"locked": {
"type": "path",
"path": child.to_string_lossy(),
"rev": REV,
"lastModified": LAST_MODIFIED,
"narHash": "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
},
"original": { "type": "path", "path": "./child" }
},
"root": { "inputs": { "child": "child" } }
},
"root": "root",
"version": 7
})
.to_string()
}
fn out_str(result: &sui_eval::value::Value, key: &str) -> String {
let attrs = result.as_attrs().expect("flake result is an attrset");
let outputs =
sui_eval::eval::force_value(attrs.get("outputs").expect("outputs present")).unwrap();
let out_attrs = outputs.as_attrs().expect("outputs is an attrset");
let v = sui_eval::eval::force_value(out_attrs.get(key).unwrap_or_else(|| panic!("{key} present")))
.unwrap();
v.as_string().expect("string output").to_string()
}
#[test]
fn locked_input_self_carries_its_own_rev_and_short_rev() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path().join("root");
build_fixture(&root);
let result =
sui_eval::builtins::evaluate_flake(&root).expect("root flake should evaluate");
let child_rev = out_str(&result, "childRev");
let child_short_rev = out_str(&result, "childShortRev");
assert_eq!(
child_rev, REV,
"a locked input flake's OWN self.rev must equal its locked node's rev. \
Got \"{child_rev}\" — the self-rev injection has regressed (nix-darwin's \
darwinRevision would fall back to null)."
);
assert_eq!(
child_short_rev, SHORT_REV,
"a locked input flake's OWN self.shortRev must equal the first 7 chars of \
its locked rev. Got \"{child_short_rev}\" — regressed (nix-darwin's \
darwinVersionSuffix would fall back to \"dirty\", diverging the toplevel \
drvPath)."
);
}