about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2023-01-31T16·43+0300
committerclbot <clbot@tvl.fyi>2023-02-01T10·01+0000
commit759f9dbf39635cd3ec630bfccdb88bb8af8b7805 (patch)
tree4a1fb0f676c43b5985a5f366d55d3b676d402ab2
parent3caa4c4aa492dd1ee51a111836365790c63bdee1 (diff)
feat(tvix/cli): implement builtins.placeholder r/5799
This doesn't require any other corresponding handling *yet*, as the
actual replacements happen in the builder logic (which we delegate to
cppnix at the moment).

Change-Id: I034147c933f05ae427c7a8794647132d108d0ede
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7972
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
-rw-r--r--tvix/cli/src/derivation.rs26
-rw-r--r--tvix/nix-compat/src/lib.rs18
2 files changed, 44 insertions, 0 deletions
diff --git a/tvix/cli/src/derivation.rs b/tvix/cli/src/derivation.rs
index 5014076ace..4fdc0b6cf7 100644
--- a/tvix/cli/src/derivation.rs
+++ b/tvix/cli/src/derivation.rs
@@ -2,6 +2,7 @@
 
 use data_encoding::BASE64;
 use nix_compat::derivation::{Derivation, Hash};
+use nix_compat::hash_placeholder;
 use std::cell::RefCell;
 use std::collections::{btree_map, BTreeSet};
 use std::rc::Rc;
@@ -250,6 +251,18 @@ fn strong_coerce_to_string(vm: &mut VM, val: &Value, ctx: &str) -> Result<String
 mod derivation_builtins {
     use super::*;
 
+    #[builtin("placeholder")]
+    fn builtin_placeholder(_: &mut VM, input: Value) -> Result<Value, ErrorKind> {
+        let placeholder = hash_placeholder(
+            input
+                .to_str()
+                .context("looking at output name in builtins.placeholder")?
+                .as_str(),
+        );
+
+        Ok(placeholder.into())
+    }
+
     /// Strictly construct a Nix derivation from the supplied arguments.
     ///
     /// This is considered an internal function, users usually want to
@@ -677,4 +690,17 @@ mod tests {
             vec!["--foo".to_string(), "42".to_string(), "--bar".to_string()]
         );
     }
+
+    #[test]
+    fn builtins_placeholder_hashes() {
+        assert_eq!(
+            hash_placeholder("out").as_str(),
+            "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
+        );
+
+        assert_eq!(
+            hash_placeholder("").as_str(),
+            "/171rf4jhx57xqz3p7swniwkig249cif71pa08p80mgaf0mqz5bmr"
+        );
+    }
 }
diff --git a/tvix/nix-compat/src/lib.rs b/tvix/nix-compat/src/lib.rs
index 60775ad90e..94fd88549a 100644
--- a/tvix/nix-compat/src/lib.rs
+++ b/tvix/nix-compat/src/lib.rs
@@ -1,4 +1,22 @@
+use sha2::{Digest, Sha256};
+
 pub mod derivation;
 pub mod nar;
 pub mod nixbase32;
 pub mod store_path;
+
+/// Nix placeholders (i.e. values returned by `builtins.placeholder`)
+/// are used to populate outputs with paths that must be
+/// string-replaced with the actual placeholders later, at runtime.
+///
+/// The actual placeholder is basically just a SHA256 hash encoded in
+/// cppnix format.
+pub fn hash_placeholder(name: &str) -> String {
+    let digest = {
+        let mut hasher = Sha256::new();
+        hasher.update(format!("nix-output:{}", name));
+        hasher.finalize()
+    };
+
+    format!("/{}", nixbase32::encode(&digest))
+}