feat(tvix/cli): add helper for populating drv output configuration

This threads through the fields that control whether a derivation is a
fixed-output derivation or not.

Change-Id: I49739de178fed9f258291174ca1a2c15a7cf5c2a
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7900
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
Vincent Ambo 2023-01-23 01:28:27 +03:00 committed by tazjin
parent fdca93d6ed
commit dfc50c9ef5
2 changed files with 125 additions and 2 deletions

View file

@ -1,8 +1,8 @@
//! Implements `builtins.derivation`, the core of what makes Nix build packages.
use std::collections::{btree_map, BTreeSet};
use tvix_derivation::Derivation;
use tvix_eval::{AddContext, ErrorKind, NixList, VM};
use tvix_derivation::{Derivation, Hash};
use tvix_eval::{AddContext, CoercionKind, ErrorKind, NixList, Value, VM};
use crate::errors::Error;
use crate::known_paths::{KnownPaths, PathType};
@ -72,6 +72,65 @@ fn populate_inputs<I: IntoIterator<Item = String>>(
}
}
/// Populate the output configuration of a derivation based on the
/// parameters passed to the call, flipping the required
/// parameters for a fixed-output derivation if necessary.
///
/// This function handles all possible combinations of the
/// parameters, including invalid ones.
fn populate_output_configuration(
drv: &mut Derivation,
vm: &mut VM,
hash: Option<&Value>, // in nix: outputHash
hash_algo: Option<&Value>, // in nix: outputHashAlgo
hash_mode: Option<&Value>, // in nix: outputHashmode
) -> Result<(), ErrorKind> {
match (hash, hash_algo, hash_mode) {
(Some(hash), Some(algo), hash_mode) => match drv.outputs.get_mut("out") {
None => return Err(Error::ConflictingOutputTypes.into()),
Some(out) => {
let algo = algo
.force(vm)?
.coerce_to_string(CoercionKind::Strong, vm)?
.as_str()
.to_string();
let hash_mode = match hash_mode {
None => None,
Some(mode) => Some(
mode.force(vm)?
.coerce_to_string(CoercionKind::Strong, vm)?
.as_str()
.to_string(),
),
};
let algo = match hash_mode.as_deref() {
None | Some("flat") => algo,
Some("recursive") => format!("r:{}", algo),
Some(other) => {
return Err(Error::InvalidOutputHashMode(other.to_string()).into())
}
};
out.hash = Some(Hash {
algo,
digest: hash
.force(vm)?
.coerce_to_string(CoercionKind::Strong, vm)?
.as_str()
.to_string(),
});
}
},
_ => {}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
@ -174,4 +233,62 @@ mod tests {
.input_derivations
.contains_key("/nix/store/aqffiyqx602lbam7n1zsaz3yrh6v08pc-bar.drv"));
}
#[test]
fn populate_output_config_std() {
let mut vm = fake_vm();
let mut drv = Derivation::default();
populate_output_configuration(&mut drv, &mut vm, None, None, None)
.expect("populate_output_configuration() should succeed");
assert_eq!(drv, Derivation::default(), "derivation should be unchanged");
}
#[test]
fn populate_output_config_fod() {
let mut vm = fake_vm();
let mut drv = Derivation::default();
drv.outputs.insert("out".to_string(), Default::default());
let hash = Value::String(
"0000000000000000000000000000000000000000000000000000000000000000".into(),
);
let algo = Value::String("sha256".into());
populate_output_configuration(&mut drv, &mut vm, Some(&hash), Some(&algo), None)
.expect("populate_output_configuration() should succeed");
let expected = Hash {
algo: "sha256".into(),
digest: "0000000000000000000000000000000000000000000000000000000000000000".into(),
};
assert_eq!(drv.outputs["out"].hash, Some(expected));
}
#[test]
fn populate_output_config_fod_recursive() {
let mut vm = fake_vm();
let mut drv = Derivation::default();
drv.outputs.insert("out".to_string(), Default::default());
let hash = Value::String(
"0000000000000000000000000000000000000000000000000000000000000000".into(),
);
let algo = Value::String("sha256".into());
let mode = Value::String("recursive".into());
populate_output_configuration(&mut drv, &mut vm, Some(&hash), Some(&algo), Some(&mode))
.expect("populate_output_configuration() should succeed");
let expected = Hash {
algo: "r:sha256".into(),
digest: "0000000000000000000000000000000000000000000000000000000000000000".into(),
};
assert_eq!(drv.outputs["out"].hash, Some(expected));
}
}

View file

@ -9,6 +9,7 @@ pub enum Error {
DuplicateEnvVar(String),
ShadowedOutput(String),
InvalidDerivation(DerivationError),
InvalidOutputHashMode(String),
}
impl Display for Error {
@ -32,6 +33,11 @@ impl Display for Error {
"the environment variable '{name}' shadows the name of an output"
),
Error::InvalidDerivation(error) => write!(f, "invalid derivation parameters: {error}"),
Error::InvalidOutputHashMode(mode) => write!(
f,
"invalid output hash mode: '{mode}', only 'recursive' and 'flat` are supported"
),
}
}
}