feat(tvix/eval): support Derivation context elements

Derivation that depends on `${d.drvPath}` generates a `NixContextElement::Derivation(drvPath)` context string.
In turn, this makes the dependent derivation depend on *ALL* outputs of that derivation.

Note that a dependency on `${d.drvPath}` generates an input source
dependency too.

This is a complete implementation of the context string system in Nix on
the "input population" side.

The test coverage of this change is taken care in cl/11264.

Change-Id: I97fe5f7c772a6b1cc4366bee071aa691a11fcde6
Signed-off-by: Ryan Lahfa <tvl@lahfa.xyz>
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11261
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
This commit is contained in:
Ryan Lahfa 2024-03-25 00:59:41 +01:00 committed by raitobezarius
parent 45925ea931
commit 94185f7560

View file

@ -1,5 +1,6 @@
//! Implements `builtins.derivation`, the core of what makes Nix build packages.
use crate::builtins::DerivationError;
use crate::known_paths::KnownPaths;
use crate::tvix_store_io::TvixStoreIO;
use bstr::BString;
use nix_compat::derivation::{Derivation, Output};
@ -19,7 +20,7 @@ const IGNORE_NULLS: &str = "__ignoreNulls";
/// Populate the inputs of a derivation from the build references
/// found when scanning the derivation's parameters and extracting their contexts.
fn populate_inputs(drv: &mut Derivation, full_context: NixContext) {
fn populate_inputs(drv: &mut Derivation, full_context: NixContext, known_paths: &KnownPaths) {
for element in full_context.iter() {
match element {
NixContextElement::Plain(source) => {
@ -57,12 +58,37 @@ fn populate_inputs(drv: &mut Derivation, full_context: NixContext) {
}
}
NixContextElement::Derivation(_drv_path) => {
// This is a hard one, it means that
// we are depending on a drvPath of ourselves
// *or* another derivation's drvPath.
// What to do here?
panic!("please do not depend on drvPath, I have 2 hours of sleep in blood");
NixContextElement::Derivation(drv_path) => {
let (derivation, _rest) =
StorePath::from_absolute_path_full(drv_path).expect("valid store path");
#[cfg(debug_assertions)]
assert!(
_rest.iter().next().is_none(),
"Extra path not empty for {}",
drv_path
);
// We need to know all the outputs *names* of that derivation.
let output_names = known_paths
.get_drv_by_drvpath(&derivation)
.expect("no known derivation associated to that derivation path")
.outputs
.keys();
// FUTUREWORK(performance): ideally, we should be able to clone
// cheaply those outputs rather than duplicate them all around.
match drv.input_derivations.entry(derivation.clone()) {
btree_map::Entry::Vacant(entry) => {
entry.insert(output_names.cloned().collect());
}
btree_map::Entry::Occupied(mut entry) => {
entry.get_mut().extend(output_names.cloned());
}
}
drv.input_sources.insert(derivation);
}
}
}
@ -416,8 +442,8 @@ pub(crate) mod derivation_builtins {
);
}
populate_inputs(&mut drv, input_context);
let mut known_paths = state.as_ref().known_paths.borrow_mut();
populate_inputs(&mut drv, input_context, &known_paths);
// At this point, derivation fields are fully populated from
// eval data structures.