diff options
Diffstat (limited to 'tvix/glue/src/builtins/derivation.rs')
-rw-r--r-- | tvix/glue/src/builtins/derivation.rs | 119 |
1 files changed, 101 insertions, 18 deletions
diff --git a/tvix/glue/src/builtins/derivation.rs b/tvix/glue/src/builtins/derivation.rs index a7742ae40a66..5bc9dab71283 100644 --- a/tvix/glue/src/builtins/derivation.rs +++ b/tvix/glue/src/builtins/derivation.rs @@ -168,14 +168,21 @@ fn handle_fixed_output( #[builtins(state = "Rc<TvixStoreIO>")] pub(crate) mod derivation_builtins { use std::collections::BTreeMap; + use std::io::Cursor; use crate::builtins::utils::{select_string, strong_importing_coerce_to_string}; + use crate::fetchurl::fetchurl_derivation_to_fetch; use super::*; use bstr::ByteSlice; - use nix_compat::store_path::hash_placeholder; + use md5::Digest; + use nix_compat::nixhash::CAHash; + use nix_compat::store_path::{build_ca_path, hash_placeholder}; + use sha2::Sha256; + use tvix_castore::Node; use tvix_eval::generators::Gen; use tvix_eval::{NixContext, NixContextElement, NixString}; + use tvix_store::proto::{NarInfo, PathInfo}; #[builtin("placeholder")] async fn builtin_placeholder(co: GenCo, input: Value) -> Result<Value, ErrorKind> { @@ -338,9 +345,9 @@ pub(crate) mod derivation_builtins { input_context.mimic(&val_str); if arg_name == "builder" { - drv.builder = val_str.to_str()?.to_owned(); + val_str.to_str()?.clone_into(&mut drv.builder); } else { - drv.system = val_str.to_str()?.to_owned(); + val_str.to_str()?.clone_into(&mut drv.system); } // Either populate drv.environment or structured_attrs. @@ -372,12 +379,12 @@ pub(crate) mod derivation_builtins { return Ok(val); } - let (val_json, mut context) = match val.into_contextful_json(&co).await? { + let (val_json, context) = match val.into_contextful_json(&co).await? { Ok(v) => v, Err(cek) => return Ok(Value::from(cek)), }; - input_context = input_context.join(&mut context); + input_context.extend(context.into_iter()); // No need to check for dups, we only iterate over every attribute name once structured_attrs.insert(arg_name.to_owned(), val_json); @@ -506,6 +513,17 @@ pub(crate) mod derivation_builtins { ))), ))); + // If the derivation is a fake derivation (builtins:fetchurl), + // synthesize a [Fetch] and add it there, too. + if drv.builder == "builtin:fetchurl" { + let (name, fetch) = + fetchurl_derivation_to_fetch(&drv).map_err(|e| ErrorKind::TvixError(Rc::new(e)))?; + + known_paths + .add_fetch(fetch, &name) + .map_err(|e| ErrorKind::TvixError(Rc::new(e)))?; + } + // Register the Derivation in known_paths. known_paths.add_derivation(drv_path, drv); @@ -513,7 +531,12 @@ pub(crate) mod derivation_builtins { } #[builtin("toFile")] - async fn builtin_to_file(co: GenCo, name: Value, content: Value) -> Result<Value, ErrorKind> { + async fn builtin_to_file( + state: Rc<TvixStoreIO>, + co: GenCo, + name: Value, + content: Value, + ) -> Result<Value, ErrorKind> { if name.is_catchable() { return Ok(name); } @@ -529,24 +552,84 @@ pub(crate) mod derivation_builtins { .to_contextful_str() .context("evaluating the `content` parameter of builtins.toFile")?; - if content.iter_derivation().count() > 0 || content.iter_single_outputs().count() > 0 { + if content.iter_ctx_derivation().count() > 0 + || content.iter_ctx_single_outputs().count() > 0 + { return Err(ErrorKind::UnexpectedContext); } - let path = - nix_compat::store_path::build_text_path(name.to_str()?, &content, content.iter_plain()) - .map_err(|_e| { - nix_compat::derivation::DerivationError::InvalidOutputName( - name.to_str_lossy().into_owned(), - ) + let store_path = state.tokio_handle.block_on(async { + // upload contents to the blobservice and create a root node + let mut blob_writer = state.blob_service.open_write().await; + + let mut r = Cursor::new(&content); + + let blob_size = tokio::io::copy(&mut r, &mut blob_writer).await?; + let blob_digest = blob_writer.close().await?; + let ca_hash = CAHash::Text(Sha256::digest(&content).into()); + + let store_path: StorePathRef = + build_ca_path(name.to_str()?, &ca_hash, content.iter_ctx_plain(), false) + .map_err(|_e| { + nix_compat::derivation::DerivationError::InvalidOutputName( + name.to_str_lossy().into_owned(), + ) + }) + .map_err(DerivationError::InvalidDerivation)?; + + let root_node = Node::File { + digest: blob_digest, + size: blob_size, + executable: false, + }; + + // calculate the nar hash + let (nar_size, nar_sha256) = state + .nar_calculation_service + .calculate_nar(&root_node) + .await + .map_err(|e| ErrorKind::TvixError(Rc::new(e)))?; + + // assemble references from plain context. + let reference_paths: Vec<StorePathRef> = content + .iter_ctx_plain() + .map(|elem| StorePathRef::from_absolute_path(elem.as_bytes())) + .collect::<Result<_, _>>() + .map_err(|e| ErrorKind::TvixError(Rc::new(e)))?; + + // persist via pathinfo service. + state + .path_info_service + .put(PathInfo { + node: Some(tvix_castore::proto::Node::from_name_and_node( + store_path.to_string().into(), + root_node, + )), + references: reference_paths + .iter() + .map(|x| bytes::Bytes::copy_from_slice(x.digest())) + .collect(), + narinfo: Some(NarInfo { + nar_size, + nar_sha256: nar_sha256.to_vec().into(), + signatures: vec![], + reference_names: reference_paths + .into_iter() + .map(|x| x.to_string()) + .collect(), + deriver: None, + ca: Some(ca_hash.into()), + }), }) - .map_err(DerivationError::InvalidDerivation)? - .to_absolute_path(); + .await + .map_err(|e| ErrorKind::TvixError(Rc::new(e)))?; - let context: NixContext = NixContextElement::Plain(path.clone()).into(); + Ok::<_, ErrorKind>(store_path) + })?; - // TODO: actually persist the file in the store at that path ... + let abs_path = store_path.to_absolute_path(); + let context: NixContext = NixContextElement::Plain(abs_path.clone()).into(); - Ok(Value::from(NixString::new_context_from(context, path))) + Ok(Value::from(NixString::new_context_from(context, abs_path))) } } |