about summary refs log tree commit diff
path: root/tvix/eval/src/builtins/mod.rs
diff options
context:
space:
mode:
authorsterni <sternenseemann@systemli.org>2022-09-13T18·11+0200
committerclbot <clbot@tvl.fyi>2022-09-15T20·58+0000
commit067f2b16f6f5d8fce73b8420a53b51a15c90f589 (patch)
treecdfa2d5a70b14d1b438769aa282273d8efc469ac /tvix/eval/src/builtins/mod.rs
parente834a2cbc47cf18d5f35bb258ccc754c54c4f4e1 (diff)
feat(tvix/eval): implement Value::coerce_to_path() r/4865
This function is necessary for all builtins that expect some form of
path as an argument. It is merely a wrapper around coerce_to_string that
can shortcut if we already have a path. The absolute path check is done
in the same way as in C++ Nix for compatibility, although it should
probably be revised in the long term (think about Windows, for example).

Since coercing to a path is not an operation possible in the language
directly, this function can live in the builtins module as the only
place it is required.

Change-Id: I69ed5455c00d193fea88b8fa83e28907a761cab5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6574
Autosubmit: sterni <sternenseemann@systemli.org>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/builtins/mod.rs')
-rw-r--r--tvix/eval/src/builtins/mod.rs26
1 files changed, 26 insertions, 0 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs
index 33abfe492d10..7a2f46e2d47d 100644
--- a/tvix/eval/src/builtins/mod.rs
+++ b/tvix/eval/src/builtins/mod.rs
@@ -5,12 +5,14 @@
 
 use std::{
     collections::{BTreeMap, HashMap},
+    path::PathBuf,
     rc::Rc,
 };
 
 use crate::{
     errors::ErrorKind,
     value::{Builtin, CoercionKind, NixAttrs, NixList, NixString, Value},
+    vm::VM,
 };
 
 use crate::arithmetic_op;
@@ -36,6 +38,30 @@ macro_rules! force {
     };
 }
 
+/// Coerce a Nix Value to a plain path, e.g. in order to access the file it
+/// points to in an I/O builtin. This coercion can _never_ be performed in
+/// a Nix program directly (i.e. the trick `path: /. + path` to convert from
+/// a string to a path wouldn't hit this code), so the target file
+/// doesn't need to be realised or imported into the Nix store.
+pub fn coerce_value_to_path(v: &Value, vm: &mut VM) -> Result<PathBuf, ErrorKind> {
+    force!(vm, v, value, {
+        match value {
+            Value::Thunk(t) => coerce_value_to_path(&t.value(), vm),
+            Value::Path(p) => Ok(p.clone()),
+            _ => value
+                .coerce_to_string(CoercionKind::Weak, vm)
+                .map(|s| PathBuf::from(s.as_str()))
+                .and_then(|path| {
+                    if path.is_absolute() {
+                        Ok(path)
+                    } else {
+                        Err(ErrorKind::NotAnAbsolutePath(path))
+                    }
+                }),
+        }
+    })
+}
+
 /// Return all pure builtins, that is all builtins that do not rely on
 /// I/O outside of the VM and which can be used in any contexts (e.g.
 /// WASM).