feat(tvix/derivation): add path_with_references

This allows the calculation of a store path for a plain string that
potentially contains references. These paths are used for
`builtins.toFile` (and potentially other features of C++ Nix).

Change-Id: Ic507c7f264f362b5e6e628255869e5a4fbe4d788
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7906
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
Vincent Ambo 2023-01-23 15:43:47 +03:00 committed by tazjin
parent be7f64ac87
commit 5d856ac2e9
3 changed files with 63 additions and 1 deletions

View file

@ -75,6 +75,32 @@ fn build_store_path(
// invalid, so map errors to a [DerivationError::InvalidOutputName].
}
/// Build a store path for a literal text file in the store that may
/// contain references.
pub fn path_with_references<'a, I: IntoIterator<Item = &'a str>, C: AsRef<[u8]>>(
name: &str,
content: C,
references: I,
) -> Result<StorePath, DerivationError> {
let mut hasher = Sha256::new();
hasher.update(content);
let content_hash = hasher.finalize_reset();
hasher.update("text");
for reference in references {
hasher.update(":");
hasher.update(reference);
}
hasher.update(&format!(":sha256:{:x}:", content_hash));
hasher.update(STORE_DIR);
hasher.update(&format!(":{}", name));
let digest = hasher.finalize();
build_store_path(false, &digest, name)
}
impl Derivation {
pub fn serialize(&self, writer: &mut impl Write) -> Result<(), fmt::Error> {
writer.write_str(write::DERIVATION_PREFIX)?;

View file

@ -10,6 +10,6 @@ mod tests;
// Public API of the crate.
pub use derivation::Derivation;
pub use derivation::{path_with_references, Derivation};
pub use errors::{DerivationError, OutputError};
pub use output::{Hash, Output};

View file

@ -305,3 +305,39 @@ fn output_path_construction() {
.expect("must succeed")
);
}
#[test]
fn path_with_zero_references() {
// This hash should match `builtins.toFile`, e.g.:
//
// nix-repl> builtins.toFile "foo" "bar"
// "/nix/store/vxjiwkjkn7x4079qvh1jkl5pn05j2aw0-foo"
let store_path = crate::path_with_references("foo", "bar", vec![])
.expect("path_with_references() should succeed");
assert_eq!(
store_path.to_absolute_path().as_str(),
"/nix/store/vxjiwkjkn7x4079qvh1jkl5pn05j2aw0-foo"
);
}
#[test]
fn path_with_non_zero_references() {
// This hash should match:
//
// nix-repl> builtins.toFile "baz" "${builtins.toFile "foo" "bar"}"
// "/nix/store/5xd714cbfnkz02h2vbsj4fm03x3f15nf-baz"
let inner = crate::path_with_references("foo", "bar", vec![])
.expect("path_with_references() should succeed");
let inner_path = inner.to_absolute_path();
let outer = crate::path_with_references("baz", &inner_path, vec![inner_path.as_str()])
.expect("path_with_references() should succeed");
assert_eq!(
outer.to_absolute_path().as_str(),
"/nix/store/5xd714cbfnkz02h2vbsj4fm03x3f15nf-baz"
);
}