about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/io.rs23
-rw-r--r--tvix/eval/src/value/mod.rs3
-rw-r--r--tvix/eval/tests/nix_oracle.rs5
3 files changed, 28 insertions, 3 deletions
diff --git a/tvix/eval/src/io.rs b/tvix/eval/src/io.rs
index 4e7404ef9c53..d20912f21f61 100644
--- a/tvix/eval/src/io.rs
+++ b/tvix/eval/src/io.rs
@@ -16,7 +16,7 @@
 //! how store paths are opened and so on.
 
 use smol_str::SmolStr;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
 use crate::errors::ErrorKind;
@@ -42,6 +42,15 @@ pub trait EvalIO {
     /// of its entries associated with their [`FileType`].
     fn read_dir(&self, path: PathBuf) -> Result<Vec<(SmolStr, FileType)>, ErrorKind>;
 
+    /// Import the given path. What this means depends on the
+    /// implementation, for example for a `std::io`-based
+    /// implementation this might be a no-op, while for a Tvix store
+    /// this might be a copy of the given files to the store.
+    ///
+    /// This is primarily used in the context of things like coercing
+    /// a local path to a string, or builtins like `path`.
+    fn import_path(&self, path: &Path) -> Result<PathBuf, ErrorKind>;
+
     /// Returns the root of the store directory, if such a thing
     /// exists in the evaluation context.
     fn store_dir(&self) -> Option<String> {
@@ -103,6 +112,12 @@ impl EvalIO for StdIO {
 
         Ok(result)
     }
+
+    // this is a no-op for `std::io`, as the user can already refer to
+    // the path directly
+    fn import_path(&self, path: &Path) -> Result<PathBuf, ErrorKind> {
+        Ok(path.to_path_buf())
+    }
 }
 
 /// Dummy implementation of [`EvalIO`], can be used in contexts where
@@ -127,4 +142,10 @@ impl EvalIO for DummyIO {
             "I/O methods are not implemented in DummyIO",
         ))
     }
+
+    fn import_path(&self, _: &Path) -> Result<PathBuf, ErrorKind> {
+        Err(ErrorKind::NotImplemented(
+            "I/O methods are not implemented in DummyIO",
+        ))
+    }
 }
diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs
index 583d0c38e46e..3e59c19c3196 100644
--- a/tvix/eval/src/value/mod.rs
+++ b/tvix/eval/src/value/mod.rs
@@ -185,7 +185,8 @@ impl Value {
             // sequences without NUL bytes, whereas Tvix only allows valid
             // Unicode. See also b/189.
             (Value::Path(p), kind) if kind != CoercionKind::ThunksOnly => {
-                Ok(p.to_string_lossy().into_owned().into())
+                let imported = vm.io().import_path(p)?;
+                Ok(imported.to_string_lossy().into_owned().into())
             }
 
             // Attribute sets can be converted to strings if they either have an
diff --git a/tvix/eval/tests/nix_oracle.rs b/tvix/eval/tests/nix_oracle.rs
index 4910a18bec08..e241a26f8ffd 100644
--- a/tvix/eval/tests/nix_oracle.rs
+++ b/tvix/eval/tests/nix_oracle.rs
@@ -40,7 +40,10 @@ fn nix_eval(expr: &str) -> String {
 #[track_caller]
 fn compare_eval(expr: &str) {
     let nix_result = nix_eval(expr);
-    let tvix_result = tvix_eval::Evaluation::new(expr, None)
+    let mut eval = tvix_eval::Evaluation::new(expr, None);
+    eval.io_handle = Box::new(tvix_eval::StdIO);
+
+    let tvix_result = eval
         .evaluate()
         .value
         .expect("tvix evaluation should succeed")