feat(tvix/eval): Implement builtins.readFileType
builtins.readFileType was added to Nix back in version 2.14. The tests were also moved out of notyetpassing in addition to the readDir fixtures they depend on. I caught a bug where we previously used std::fs::metadata (via the .metadata() method on File) which follows symlinks so it would always return false for is_symlink(). Instead we now use std::fs::symlink_metadata directly which does not follow symlinks, so tests now pass. This wasn't an issue for builtins.readDir as it uses walkdir and walkdir doesn't follow symlinks either. Change-Id: I58eb97bdb5ec95df4f6882f495f8c572fe7c6793 Reviewed-on: https://cl.tvl.fyi/c/depot/+/12130 Reviewed-by: flokli <flokli@flokli.de> Autosubmit: Ilan Joselevich <personal@ilanjoselevich.com> Tested-by: BuildkiteCI
This commit is contained in:
parent
9c4b57ac63
commit
3511e328ec
10 changed files with 47 additions and 3 deletions
|
@ -81,6 +81,18 @@ mod impure_builtins {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[builtin("readFileType")]
|
||||
async fn builtin_read_file_type(co: GenCo, path: Value) -> Result<Value, ErrorKind> {
|
||||
match coerce_value_to_path(&co, path).await? {
|
||||
Err(cek) => Ok(Value::from(cek)),
|
||||
Ok(path) => Ok(Value::from(
|
||||
generators::request_read_file_type(&co, path)
|
||||
.await
|
||||
.to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return all impure builtins, that is all builtins which may perform I/O
|
||||
|
|
|
@ -26,7 +26,7 @@ use std::os::unix::ffi::OsStringExt;
|
|||
#[cfg(feature = "impure")]
|
||||
use std::fs::File;
|
||||
|
||||
/// Types of files as represented by `builtins.readDir` in Nix.
|
||||
/// Types of files as represented by `builtins.readFileType` and `builtins.readDir` in Nix.
|
||||
#[derive(Debug)]
|
||||
pub enum FileType {
|
||||
Directory,
|
||||
|
@ -120,7 +120,7 @@ impl EvalIO for StdIO {
|
|||
}
|
||||
|
||||
fn file_type(&self, path: &Path) -> io::Result<FileType> {
|
||||
let file_type = File::open(path)?.metadata()?.file_type();
|
||||
let file_type = std::fs::symlink_metadata(path)?;
|
||||
|
||||
Ok(if file_type.is_dir() {
|
||||
FileType::Directory
|
||||
|
|
|
@ -121,6 +121,9 @@ pub enum VMRequest {
|
|||
/// Request serialisation of a value to JSON, according to the
|
||||
/// slightly odd Nix evaluation rules.
|
||||
ToJson(Value),
|
||||
|
||||
/// Request the VM for the file type of the given path.
|
||||
ReadFileType(PathBuf),
|
||||
}
|
||||
|
||||
/// Human-readable representation of a generator message, used by observers.
|
||||
|
@ -178,6 +181,7 @@ impl Display for VMRequest {
|
|||
VMRequest::Span => write!(f, "span"),
|
||||
VMRequest::TryForce(v) => write!(f, "try_force({})", v.type_of()),
|
||||
VMRequest::ToJson(v) => write!(f, "to_json({})", v.type_of()),
|
||||
VMRequest::ReadFileType(p) => write!(f, "read_file_type({})", p.to_string_lossy()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,6 +206,8 @@ pub enum VMResponse {
|
|||
|
||||
/// [std::io::Reader] produced by the VM in response to some IO operation.
|
||||
Reader(Box<dyn std::io::Read>),
|
||||
|
||||
FileType(FileType),
|
||||
}
|
||||
|
||||
impl Display for VMResponse {
|
||||
|
@ -213,6 +219,7 @@ impl Display for VMResponse {
|
|||
VMResponse::Directory(d) => write!(f, "dir(len = {})", d.len()),
|
||||
VMResponse::Span(_) => write!(f, "span"),
|
||||
VMResponse::Reader(_) => write!(f, "reader"),
|
||||
VMResponse::FileType(t) => write!(f, "file_type({})", t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,6 +504,20 @@ where
|
|||
});
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
VMRequest::ReadFileType(path) => {
|
||||
let file_type = self
|
||||
.io_handle
|
||||
.as_ref()
|
||||
.file_type(&path)
|
||||
.map_err(|e| ErrorKind::IO {
|
||||
path: Some(path),
|
||||
error: e.into(),
|
||||
})
|
||||
.with_span(span, self)?;
|
||||
|
||||
message = VMResponse::FileType(file_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -791,6 +812,17 @@ pub(crate) async fn request_to_json(
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "impure"), allow(unused))]
|
||||
pub(crate) async fn request_read_file_type(co: &GenCo, path: PathBuf) -> FileType {
|
||||
match co.yield_(VMRequest::ReadFileType(path)).await {
|
||||
VMResponse::FileType(file_type) => file_type,
|
||||
msg => panic!(
|
||||
"Tvix bug: VM responded with incorrect generator message: {}",
|
||||
msg
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Call the given value as if it was an attribute set containing a functor. The
|
||||
/// arguments must already be prepared on the stack when a generator frame from
|
||||
/// this function is invoked.
|
||||
|
|
|
@ -70,7 +70,7 @@ let
|
|||
"eval-okay-cycle-display-cpp-nix-2.13.nix" = [ nix_2_3 ];
|
||||
# builtins.replaceStrings becomes lazier in Nix 2.16
|
||||
"eval-okay-replacestrings.nix" = [ nix_2_3 ];
|
||||
# builtins.readFileType is added in Nix 2.15
|
||||
# builtins.readFileType is added in Nix 2.14
|
||||
"eval-okay-readFileType.nix" = [ nix_2_3 ];
|
||||
# builtins.fromTOML gains support for timestamps in Nix 2.16
|
||||
"eval-okay-fromTOML-timestamps.nix" = [ nix_2_3 ];
|
||||
|
|
Loading…
Reference in a new issue