refactor(tvix/eval): use EvalIO::read_dir
for equivalent builtin
Change-Id: I6d782c07166f51587d2f1d06607823268debb5d5 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7574 Reviewed-by: grfn <grfn@gws.fyi> Tested-by: BuildkiteCI
This commit is contained in:
parent
51deadd983
commit
4cb9ada0df
2 changed files with 77 additions and 30 deletions
|
@ -1,14 +1,17 @@
|
|||
use builtin_macros::builtins;
|
||||
use smol_str::SmolStr;
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
env, io,
|
||||
rc::{Rc, Weak},
|
||||
env,
|
||||
rc::Weak,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
compiler::GlobalsMap,
|
||||
errors::ErrorKind,
|
||||
io::FileType,
|
||||
observer::NoOpObserver,
|
||||
spans::LightSpan,
|
||||
value::{Builtin, BuiltinArgument, NixAttrs, Thunk},
|
||||
|
@ -35,33 +38,22 @@ mod impure_builtins {
|
|||
#[builtin("readDir")]
|
||||
fn builtin_read_dir(vm: &mut VM, path: Value) -> Result<Value, ErrorKind> {
|
||||
let path = coerce_value_to_path(&path, vm)?;
|
||||
let mk_err = |err: io::Error| ErrorKind::IO {
|
||||
path: Some(path.clone()),
|
||||
error: Rc::new(err),
|
||||
};
|
||||
|
||||
let res = path.read_dir().map_err(mk_err)?.into_iter().flat_map(
|
||||
|entry| -> Result<(String, &str), ErrorKind> {
|
||||
let entry = entry.map_err(mk_err)?;
|
||||
let file_type = entry
|
||||
.metadata()
|
||||
.map_err(|err| ErrorKind::IO {
|
||||
path: Some(entry.path()),
|
||||
error: Rc::new(err),
|
||||
})?
|
||||
.file_type();
|
||||
let val = if file_type.is_dir() {
|
||||
"directory"
|
||||
} else if file_type.is_file() {
|
||||
"regular"
|
||||
} else if file_type.is_symlink() {
|
||||
"symlink"
|
||||
} else {
|
||||
"unknown"
|
||||
};
|
||||
Ok((entry.file_name().to_string_lossy().to_string(), val))
|
||||
},
|
||||
);
|
||||
let res = vm.io().read_dir(path)?.into_iter().map(|(name, ftype)| {
|
||||
(
|
||||
name,
|
||||
Value::String(
|
||||
SmolStr::new(match ftype {
|
||||
FileType::Directory => "directory",
|
||||
FileType::Regular => "regular",
|
||||
FileType::Symlink => "symlink",
|
||||
FileType::Unknown => "unknown",
|
||||
})
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
Ok(Value::attrs(NixAttrs::from_iter(res)))
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,21 @@
|
|||
//! In the context of Nix builds, callers also use this interface to determine
|
||||
//! how store paths are opened and so on.
|
||||
|
||||
use smol_str::SmolStr;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::errors::ErrorKind;
|
||||
|
||||
/// Types of files as represented by `builtins.readDir` in Nix.
|
||||
#[derive(Debug)]
|
||||
pub enum FileType {
|
||||
Directory,
|
||||
Regular,
|
||||
Symlink,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Defines how filesystem interaction occurs inside of tvix-eval.
|
||||
pub trait EvalIO {
|
||||
/// Verify whether the file at the specified path exists.
|
||||
|
@ -26,6 +37,10 @@ pub trait EvalIO {
|
|||
|
||||
/// Read the file at the specified path to a string.
|
||||
fn read_to_string(&self, path: PathBuf) -> Result<String, ErrorKind>;
|
||||
|
||||
/// Read the directory at the specified path and return the names
|
||||
/// of its entries associated with their [`FileType`].
|
||||
fn read_dir(&self, path: PathBuf) -> Result<Vec<(SmolStr, FileType)>, ErrorKind>;
|
||||
}
|
||||
|
||||
/// Implementation of [`EvalIO`] that simply uses the equivalent
|
||||
|
@ -38,16 +53,50 @@ impl EvalIO for StdIO {
|
|||
fn path_exists(&self, path: PathBuf) -> Result<bool, ErrorKind> {
|
||||
path.try_exists().map_err(|e| ErrorKind::IO {
|
||||
path: Some(path),
|
||||
error: std::rc::Rc::new(e),
|
||||
error: Rc::new(e),
|
||||
})
|
||||
}
|
||||
|
||||
fn read_to_string(&self, path: PathBuf) -> Result<String, ErrorKind> {
|
||||
std::fs::read_to_string(&path).map_err(|e| ErrorKind::IO {
|
||||
path: Some(path),
|
||||
error: std::rc::Rc::new(e),
|
||||
error: Rc::new(e),
|
||||
})
|
||||
}
|
||||
|
||||
fn read_dir(&self, path: PathBuf) -> Result<Vec<(SmolStr, FileType)>, ErrorKind> {
|
||||
let mut result = vec![];
|
||||
|
||||
let mk_err = |err| ErrorKind::IO {
|
||||
path: Some(path.clone()),
|
||||
error: Rc::new(err),
|
||||
};
|
||||
|
||||
for entry in path.read_dir().map_err(mk_err)? {
|
||||
let entry = entry.map_err(mk_err)?;
|
||||
let file_type = entry
|
||||
.metadata()
|
||||
.map_err(|err| ErrorKind::IO {
|
||||
path: Some(entry.path()),
|
||||
error: Rc::new(err),
|
||||
})?
|
||||
.file_type();
|
||||
|
||||
let val = if file_type.is_dir() {
|
||||
FileType::Directory
|
||||
} else if file_type.is_file() {
|
||||
FileType::Regular
|
||||
} else if file_type.is_symlink() {
|
||||
FileType::Symlink
|
||||
} else {
|
||||
FileType::Unknown
|
||||
};
|
||||
|
||||
result.push((SmolStr::new(entry.file_name().to_string_lossy()), val));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy implementation of [`EvalIO`], can be used in contexts where
|
||||
|
@ -66,4 +115,10 @@ impl EvalIO for DummyIO {
|
|||
"I/O methods are not implemented in DummyIO",
|
||||
))
|
||||
}
|
||||
|
||||
fn read_dir(&self, _: PathBuf) -> Result<Vec<(SmolStr, FileType)>, ErrorKind> {
|
||||
Err(ErrorKind::NotImplemented(
|
||||
"I/O methods are not implemented in DummyIO",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue