snix_glue/builtins/
mod.rs1use std::rc::Rc;
4
5use crate::snix_store_io::SnixStoreIO;
6
7mod derivation;
8mod errors;
9mod fetchers;
10mod import;
11mod utils;
12
13pub use errors::{DerivationError, FetcherError, ImportError};
14
15pub fn add_derivation_builtins<'co, 'ro, 'env, IO>(
24 eval_builder: snix_eval::EvaluationBuilder<'co, 'ro, 'env, IO>,
25 io: Rc<SnixStoreIO>,
26) -> snix_eval::EvaluationBuilder<'co, 'ro, 'env, IO> {
27 eval_builder
28 .add_builtins(derivation::derivation_builtins::builtins(Rc::clone(&io)))
29 .add_src_builtin("derivation", include_str!("derivation.nix"))
31}
32
33pub fn add_fetcher_builtins<'co, 'ro, 'env, IO>(
39 eval_builder: snix_eval::EvaluationBuilder<'co, 'ro, 'env, IO>,
40 io: Rc<SnixStoreIO>,
41) -> snix_eval::EvaluationBuilder<'co, 'ro, 'env, IO> {
42 eval_builder.add_builtins(fetchers::fetcher_builtins::builtins(Rc::clone(&io)))
43}
44
45pub fn add_import_builtins<'co, 'ro, 'env, IO>(
55 eval_builder: snix_eval::EvaluationBuilder<'co, 'ro, 'env, IO>,
56 io: Rc<SnixStoreIO>,
57) -> snix_eval::EvaluationBuilder<'co, 'ro, 'env, IO> {
58 eval_builder.add_builtins(import::import_builtins(io))
59}
60
61#[cfg(test)]
62mod tests {
63 use std::{rc::Rc, sync::Arc};
64
65 use crate::snix_store_io::SnixStoreIO;
66
67 use super::{add_derivation_builtins, add_fetcher_builtins, add_import_builtins};
68 use clap::Parser;
69 use nix_compat::store_path::hash_placeholder;
70 use rstest::rstest;
71 use snix_build::buildservice::DummyBuildService;
72 use snix_eval::{EvalIO, EvaluationResult};
73 use snix_store::utils::{ServiceUrlsMemory, construct_services};
74
75 fn eval(str: &str) -> EvaluationResult {
79 let runtime = tokio::runtime::Runtime::new().expect("Failed to build a Tokio runtime");
81 let (blob_service, directory_service, path_info_service, nar_calculation_service) = runtime
82 .block_on(async {
83 construct_services(ServiceUrlsMemory::parse_from(std::iter::empty::<&str>())).await
84 })
85 .expect("Failed to construct store services in memory");
86
87 let io = Rc::new(SnixStoreIO::new(
88 blob_service,
89 directory_service,
90 path_info_service,
91 nar_calculation_service.into(),
92 Arc::<DummyBuildService>::default(),
93 runtime.handle().clone(),
94 Vec::new(),
95 ));
96
97 let mut eval_builder = snix_eval::Evaluation::builder(io.clone() as Rc<dyn EvalIO>);
98 eval_builder = add_derivation_builtins(eval_builder, Rc::clone(&io));
99 eval_builder = add_fetcher_builtins(eval_builder, Rc::clone(&io));
100 eval_builder = add_import_builtins(eval_builder, io);
101 let eval = eval_builder.build();
102
103 eval.evaluate(str, None)
105 }
106
107 #[test]
108 fn builtins_placeholder_hashes() {
109 assert_eq!(
110 hash_placeholder("out").as_str(),
111 "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
112 );
113
114 assert_eq!(
115 hash_placeholder("").as_str(),
116 "/171rf4jhx57xqz3p7swniwkig249cif71pa08p80mgaf0mqz5bmr"
117 );
118 }
119
120 #[rstest]
122 #[case::r_sha256_wrong_padding(r#"(builtins.derivation { name = "foo"; builder = "/bin/sh"; system = "x86_64-linux"; outputHashMode = "recursive"; outputHashAlgo = "sha256"; outputHash = "sha256-fgIr3TyFGDAXP5+qoAaiMKDg/a1MlT6Fv/S/DaA24S8===="; }).outPath"#, "/nix/store/xm1l9dx4zgycv9qdhcqqvji1z88z534b-foo")]
123 fn builtins_derivation_hash_wrong_padding_warn(
124 #[case] code: &str,
125 #[case] expected_path: &str,
126 ) {
127 let eval_result = eval(code);
128
129 let value = eval_result.value.expect("must succeed");
130
131 match value {
132 snix_eval::Value::String(s) => {
133 assert_eq!(*s, expected_path);
134 }
135 _ => panic!("unexpected value type: {value:?}"),
136 }
137
138 assert!(
139 !eval_result.warnings.is_empty(),
140 "warnings should not be empty"
141 );
142 }
143}