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:
		
							parent
							
								
									fdca93d6ed
								
							
						
					
					
						commit
						dfc50c9ef5
					
				
					 2 changed files with 125 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -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));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue