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.
 | 
					//! Implements `builtins.derivation`, the core of what makes Nix build packages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::collections::{btree_map, BTreeSet};
 | 
					use std::collections::{btree_map, BTreeSet};
 | 
				
			||||||
use tvix_derivation::Derivation;
 | 
					use tvix_derivation::{Derivation, Hash};
 | 
				
			||||||
use tvix_eval::{AddContext, ErrorKind, NixList, VM};
 | 
					use tvix_eval::{AddContext, CoercionKind, ErrorKind, NixList, Value, VM};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::errors::Error;
 | 
					use crate::errors::Error;
 | 
				
			||||||
use crate::known_paths::{KnownPaths, PathType};
 | 
					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)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
| 
						 | 
					@ -174,4 +233,62 @@ mod tests {
 | 
				
			||||||
            .input_derivations
 | 
					            .input_derivations
 | 
				
			||||||
            .contains_key("/nix/store/aqffiyqx602lbam7n1zsaz3yrh6v08pc-bar.drv"));
 | 
					            .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),
 | 
					    DuplicateEnvVar(String),
 | 
				
			||||||
    ShadowedOutput(String),
 | 
					    ShadowedOutput(String),
 | 
				
			||||||
    InvalidDerivation(DerivationError),
 | 
					    InvalidDerivation(DerivationError),
 | 
				
			||||||
 | 
					    InvalidOutputHashMode(String),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Display for Error {
 | 
					impl Display for Error {
 | 
				
			||||||
| 
						 | 
					@ -32,6 +33,11 @@ impl Display for Error {
 | 
				
			||||||
                "the environment variable '{name}' shadows the name of an output"
 | 
					                "the environment variable '{name}' shadows the name of an output"
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            Error::InvalidDerivation(error) => write!(f, "invalid derivation parameters: {error}"),
 | 
					            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