refactor(tvix/nix-compat): -derivation::Hash, +NixHash

This stops using our own custom Hash structure, which was mostly only
used because we had to parse the JSON representation somehow.

Since cl/8217, there's a `NixHash` struct, which is better suited to
hold this data. Converting the format requires a bit of serde labor
though, but that only really matters when interacting with JSON
representations (which we mostly don't).

Change-Id: Idc5ee511e36e6726c71f66face8300a441b0bf4c
Reviewed-on: https://cl.tvl.fyi/c/depot/+/8304
Autosubmit: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
This commit is contained in:
Florian Klink 2023-03-14 17:16:05 +01:00 committed by clbot
parent e82385dbe5
commit b55d1f97ce
8 changed files with 201 additions and 87 deletions

View file

@ -1,5 +1,5 @@
use crate::{
nixhash::NixHash,
nixhash::HashAlgo,
store_path::{self, StorePath},
};
use serde::{Deserialize, Serialize};
@ -17,8 +17,9 @@ mod write;
mod tests;
// Public API of the crate.
pub use crate::nixhash::{NixHash, NixHashWithMode};
pub use errors::{DerivationError, OutputError};
pub use output::{Hash, Output};
pub use output::Output;
pub use utils::path_with_references;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
@ -75,23 +76,22 @@ impl Derivation {
buffer
}
/// Returns the fixed output path and its hash
// (if the Derivation is fixed output),
/// or None if there is no fixed output.
/// Returns the fixed output path and its [NixHashWithMode]
/// (if the Derivation is fixed output), or None if there is no fixed output.
/// This takes some shortcuts in case more than one output exists, as this
/// can't be a valid fixed-output Derivation.
pub fn get_fixed_output(&self) -> Option<(&String, &Hash)> {
pub fn get_fixed_output(&self) -> Option<(&String, &NixHashWithMode)> {
if self.outputs.len() != 1 {
return None;
}
if let Some(out_output) = self.outputs.get("out") {
if let Some(out_output_hash) = &out_output.hash {
if let Some(out_output_hash) = &out_output.hash_with_mode {
return Some((&out_output.path, out_output_hash));
}
// There has to be a hash, otherwise it would not be FOD
}
return None;
None
}
/// Returns the drv path of a Derivation struct.
@ -160,8 +160,6 @@ impl Derivation {
/// `fixed:out:${algo}:${digest}:${fodPath}` string is hashed instead of
/// the A-Term.
///
/// TODO: what's the representation of ${digest}?
///
/// If the derivation is not a fixed derivation, it's up to the caller of
/// this function to provide a lookup function to lookup these calculation
/// results of parent derivations at `fn_get_hash_derivation_modulo` (by
@ -175,8 +173,9 @@ impl Derivation {
// Fixed-output derivations return a fixed hash
Some((fixed_output_path, fixed_output_hash)) => {
hasher.update(format!(
"fixed:out:{}:{}:{}",
&fixed_output_hash.algo, &fixed_output_hash.digest, fixed_output_path,
"fixed:out:{}:{}",
fixed_output_hash.to_nix_hash_string(),
fixed_output_path
));
hasher.finalize()
}
@ -196,7 +195,7 @@ impl Derivation {
for (drv_path, output_names) in &self.input_derivations {
replaced_input_derivations.insert(
data_encoding::HEXLOWER
.encode(&fn_get_derivation_or_fod_hash(&drv_path).digest),
.encode(&fn_get_derivation_or_fod_hash(drv_path).digest),
output_names.clone(),
);
}
@ -255,7 +254,7 @@ impl Derivation {
output_path_name.push_str(output_name);
}
let s = &format!(
let fp = &format!(
"output:{}:{}:{}:{}",
output_name,
derivation_or_fod_hash.to_nix_hash_string(),
@ -264,7 +263,7 @@ impl Derivation {
);
let abs_store_path =
utils::build_store_path(false, s, &output_path_name)?.to_absolute_path();
utils::build_store_path(false, fp, &output_path_name)?.to_absolute_path();
output.path = abs_store_path.clone();
self.environment
@ -277,33 +276,41 @@ impl Derivation {
// footgun prevention mechanism.
assert!(fixed_output_path.is_empty());
let s = {
let mut s = String::new();
let fp = {
let mut fp = String::new();
// Fixed-output derivation.
// There's two different hashing strategies in place, depending on the value of hash.algo.
// There's two different hashing strategies in place,
// depending on whether the hash is recursive AND sha256 or anything else.
// This code is _weird_ but it is what Nix is doing. See:
// https://github.com/NixOS/nix/blob/1385b2007804c8a0370f2a6555045a00e34b07c7/src/libstore/store-api.cc#L178-L196
if fixed_output_hash.algo == "r:sha256" {
s.push_str(&format!(
"source:sha256:{}",
fixed_output_hash.digest, // lowerhex
));
if let NixHashWithMode::Recursive(recursive_hash) = fixed_output_hash {
if recursive_hash.algo == HashAlgo::Sha256 {
fp.push_str(&format!("source:{}", recursive_hash.to_nix_hash_string()));
} else {
// This is similar to the FOD case, with an empty fixed_output_path.
fp.push_str(&format!(
"output:out:{}",
derivation_or_fod_hash.to_nix_hash_string(),
));
}
} else {
s.push_str("output:out:");
// This is drv_replacement for FOD, with an empty fixed_output_path.
s.push_str(&derivation_or_fod_hash.to_nix_hash_string());
// This is similar to the FOD case, with an empty fixed_output_path.
fp.push_str(&format!(
"output:out:{}",
derivation_or_fod_hash.to_nix_hash_string(),
));
}
s.push_str(&format!(":{}:{}", store_path::STORE_DIR, name));
s
fp.push_str(&format!(":{}:{}", store_path::STORE_DIR, name));
fp
};
let abs_store_path = utils::build_store_path(false, &s, name)?.to_absolute_path();
let abs_store_path = utils::build_store_path(false, &fp, name)?.to_absolute_path();
self.outputs.insert(
"out".to_string(),
Output {
path: abs_store_path.clone(),
hash: Some(fixed_output_hash.clone()),
hash_with_mode: Some(fixed_output_hash.clone()),
},
);
self.environment.insert("out".to_string(), abs_store_path);