about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-12-12T21·12+0300
committertazjin <tazjin@tvl.su>2022-12-21T22·59+0000
commit270b1084e890d2c69456d342e6e2cad7e13ad9a7 (patch)
tree9e870b0e2181454188276d02488fc722565a6a8e
parentedd13573f523a3a03346d6737081466bc9c5299d (diff)
feat(tvix/eval): use `EvalIO::import_path` when coercing paths r/5467
This "ties the knot" of importing files into a store when referring
to them through path literals, e.g. inside of strings.

I'm not yet sure if this interface is sufficient for
builtins.path (which we haven't implemented at all yet), but it's
enough to wire up eval & store initially.

In the default implementations nothing interesting happens in this
function at all.

Change-Id: Ie01ff4161617d1e743a68dbd1a5e54c1b40c0990
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7582
Reviewed-by: grfn <grfn@gws.fyi>
Tested-by: BuildkiteCI
-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 4e7404ef9c..d20912f21f 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 583d0c38e4..3e59c19c31 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 4910a18bec..e241a26f8f 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")